diff options
Diffstat (limited to 'runtime')
77 files changed, 44645 insertions, 0 deletions
diff --git a/runtime/CFGregorianDateCreate.hpp b/runtime/CFGregorianDateCreate.hpp new file mode 100644 index 0000000..1634510 --- /dev/null +++ b/runtime/CFGregorianDateCreate.hpp @@ -0,0 +1,303 @@ +/* Arrays of asctime-date day and month strs, rfc1123-date day and month strs, and rfc850-date day and month strs. */ +static const char* kDayStrs[] = { + "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday", + "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; + +static const char* kMonthStrs[] = { + "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + +/* NOTE that these are ordered this way on purpose. */ +static const char* kUSTimeZones[] = {"PST", "PDT", "MST", "MDT", "CST", "CDT", "EST", "EDT"}; + + +/* extern */ const UInt8* +_CFGregorianDateCreateWithBytes(CFAllocatorRef alloc, const UInt8* bytes, CFIndex length, CFGregorianDate* date, CFTimeZoneRef* tz) { + + UInt8 buffer[256]; /* Any dates longer than this are not understood. */ + + length = (length == 256) ? 255 : length; + memmove(buffer, bytes, length); + buffer[length] = '\0'; /* Guarantees every compare will fail if trying to index off the end. */ + + memset(date, 0, sizeof(date[0])); + if (tz) *tz = NULL; + + do { + size_t i; + CFIndex scan = 0; + UInt8 c = buffer[scan]; + + /* Skip leading whitespace */ + while (isspace(c)) + c = buffer[++scan]; + + /* Check to see if there is a weekday up front. */ + if (!isdigit(c)) { + + for (i = 0; i < (sizeof(kDayStrs) / sizeof(kDayStrs[0])); i++) { + if (!memcmp(kDayStrs[i], &buffer[scan], strlen(kDayStrs[i]))) + break; + } + + if (i >=(sizeof(kDayStrs) / sizeof(kDayStrs[0]))) + break; + + scan += strlen(kDayStrs[i]); + c = buffer[scan]; + + while (isspace(c) || c == ',') + c = buffer[++scan]; + } + + /* check for asctime where month comes first */ + if (!isdigit(c)) { + + for (i = 0; i < (sizeof(kMonthStrs) / sizeof(kMonthStrs[0])); i++) { + if (!memcmp(kMonthStrs[i], &buffer[scan], strlen(kMonthStrs[i]))) + break; + } + + if (i >= (sizeof(kMonthStrs) / sizeof(kMonthStrs[0]))) + break; + + date->month = (i % 12) + 1; + + scan += strlen(kMonthStrs[i]); + c = buffer[scan]; + + while (isspace(c)) + c = buffer[++scan]; + + if (!isdigit(c)) + break; + } + + /* Read the day of month */ + for (i = 0; isdigit(c) && (i < 2); i++) { + date->day *= 10; + date->day += c - '0'; + c = buffer[++scan]; + } + + while (isspace(c) || c == '-') + c = buffer[++scan]; + + /* Not asctime so now comes the month. */ + if (date->month == 0) { + + if (isdigit(c)) { + for (i = 0; isdigit(c) && (i < 2); i++) { + date->month *= 10; + date->month += c - '0'; + c = buffer[++scan]; + } + } + else { + for (i = 0; i < (sizeof(kMonthStrs) / sizeof(kMonthStrs[0])); i++) { + if (!memcmp(kMonthStrs[i], &buffer[scan], strlen(kMonthStrs[i]))) + break; + } + + if (i >= (sizeof(kMonthStrs) / sizeof(kMonthStrs[0]))) + break; + + date->month = (i % 12) + 1; + + scan += strlen(kMonthStrs[i]); + c = buffer[scan]; + } + + while (isspace(c) || c == '-') + c = buffer[++scan]; + + /* Read the year */ + for (i = 0; isdigit(c) && (i < 4); i++) { + date->year *= 10; + date->year += c - '0'; + c = buffer[++scan]; + } + + while (isspace(c)) + c = buffer[++scan]; + } + + /* Read the hours */ + for (i = 0; isdigit(c) && (i < 2); i++) { + date->hour *= 10; + date->hour += c - '0'; + c = buffer[++scan]; + } + + if (c != ':') + break; + c = buffer[++scan]; + + /* Read the minutes */ + for (i = 0; isdigit(c) && (i < 2); i++) { + date->minute *= 10; + date->minute += c - '0'; + c = buffer[++scan]; + } + + if (c == ':') { + + c = buffer[++scan]; + + /* Read the seconds */ + for (i = 0; isdigit(c) && (i < 2); i++) { + date->second *= 10; + date->second += c - '0'; + c = buffer[++scan]; + } + c = buffer[++scan]; + } + + /* If haven't read the year yet, now is the time. */ + if (date->year == 0) { + + while (isspace(c)) + c = buffer[++scan]; + + /* Read the year */ + for (i = 0; isdigit(c) && (i < 4); i++) { + date->year *= 10; + date->year += c - '0'; + c = buffer[++scan]; + } + } + + if (date->year && date->year < 100) { + + if (date->year < 70) + date->year += 2000; /* My CC is still using 2-digit years! */ + else + date->year += 1900; /* Bad 2 byte clients */ + } + + while (isspace(c)) + c = buffer[++scan]; + + if (c && tz) { + + /* If it has absolute offset, read the hours and minutes. */ + if ((c == '+') || (c == '-')) { + + char sign = c; + CFTimeInterval minutes = 0, offset = 0; + + c = buffer[++scan]; + + /* Read the hours */ + for (i = 0; isdigit(c) && (i < 2); i++) { + offset *= 10; + offset += c - '0'; + c = buffer[++scan]; + } + + /* Read the minutes */ + for (i = 0; isdigit(c) && (i < 2); i++) { + minutes *= 10; + minutes += c - '0'; + c = buffer[++scan]; + } + + offset *= 60; + offset += minutes; + + if (sign == '-') offset *= -60; + else offset *= 60; + + *tz = CFTimeZoneCreateWithTimeIntervalFromGMT(alloc, offset); + } + + /* If it's not GMT/UT time, need to parse the alpha offset. */ + else if (!strncmp((const char*)(&buffer[scan]), "UT", 2)) { + *tz = CFTimeZoneCreateWithTimeIntervalFromGMT(alloc, 0); + scan += 2; + } + + else if (!strncmp((const char*)(&buffer[scan]), "GMT", 3)) { + *tz = CFTimeZoneCreateWithTimeIntervalFromGMT(alloc, 0); + scan += 3; + } + + else if (isalpha(c)) { + + UInt8 next = buffer[scan + 1]; + + /* Check for military time. */ + if ((c != 'J') && (!next || isspace(next) || (next == '*'))) { + + if (c == 'Z') + *tz = CFTimeZoneCreateWithTimeIntervalFromGMT(alloc, 0); + + else { + + CFTimeInterval offset = (c < 'N') ? (c - 'A' + 1) : ('M' - c); + + offset *= 60; + + if (next == '*') { + scan++; + offset = (offset < 0) ? offset - 30 : offset + 30; + } + + offset *= 60; + + *tz = CFTimeZoneCreateWithTimeIntervalFromGMT(alloc, 0); + } + } + + else { + + for (i = 0; i < (sizeof(kUSTimeZones) / sizeof(kUSTimeZones[0])); i++) { + + if (!memcmp(kUSTimeZones[i], &buffer[scan], strlen(kUSTimeZones[i]))) { + + *tz = CFTimeZoneCreateWithTimeIntervalFromGMT(alloc, (-8 + (i >> 2) + (i & 0x1)) * 3600); + + scan += strlen(kUSTimeZones[i]); + + break; + } + } + } + } + } + + if (!CFGregorianDateIsValid(*date, kCFGregorianAllUnits)) + break; + + return bytes + scan; + + } while (1); + + memset(date, 0, sizeof(date[0])); + if (tz) { + if (*tz) CFRelease(*tz); + *tz = NULL; + } + + return bytes; +} + +/* extern */ CFIndex +_CFGregorianDateCreateWithString(CFAllocatorRef alloc, CFStringRef str, CFGregorianDate* date, CFTimeZoneRef* tz) { + + UInt8 buffer[256]; /* Any dates longer than this are not understood. */ + CFIndex length = CFStringGetLength(str); + CFIndex result = 0; + + CFStringGetBytes(str, CFRangeMake(0, length), kCFStringEncodingASCII, 0, FALSE, buffer, sizeof(buffer), &length); + + if (length) + result = _CFGregorianDateCreateWithBytes(alloc, buffer, length, date, tz) - buffer; + + else { + memset(date, 0, sizeof(date[0])); + if (tz) *tz = NULL; + } + + return result; +} diff --git a/runtime/VMProtect.Runtime/Core.cs b/runtime/VMProtect.Runtime/Core.cs new file mode 100644 index 0000000..97bb3d2 --- /dev/null +++ b/runtime/VMProtect.Runtime/Core.cs @@ -0,0 +1,526 @@ +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>(); + } +}
\ No newline at end of file diff --git a/runtime/VMProtect.Runtime/CpuId.cs b/runtime/VMProtect.Runtime/CpuId.cs new file mode 100644 index 0000000..4031bd3 --- /dev/null +++ b/runtime/VMProtect.Runtime/CpuId.cs @@ -0,0 +1,87 @@ +using System; +using System.Runtime.InteropServices; + +// ReSharper disable once CheckNamespace +namespace VMProtect +{ + public static class CpuId + { + public static int[] Invoke(int level) + { + var codePointer = IntPtr.Zero; + try + { + // compile + byte[] codeBytes; + if (IntPtr.Size == 4) + { + codeBytes = new byte[30]; + codeBytes[0] = 0x55; // push ebp + codeBytes[1] = 0x8B; codeBytes[2] = 0xEC; // mov ebp,esp + codeBytes[3] = 0x53; // push ebx + codeBytes[4] = 0x57; // push edi + codeBytes[5] = 0x8B; codeBytes[6] = 0x45; codeBytes[7] = 0x08; // mov eax, dword ptr [ebp+8] (move level into eax) + codeBytes[8] = 0x0F; codeBytes[9] = 0xA2; // cpuid + codeBytes[10] = 0x8B; codeBytes[11] = 0x7D; codeBytes[12] = 0x0C; // mov edi, dword ptr [ebp+12] (move address of buffer into edi) + codeBytes[13] = 0x89; codeBytes[14] = 0x07; // mov dword ptr [edi+0], eax (write eax, ... to buffer) + codeBytes[15] = 0x89; codeBytes[16] = 0x5F; codeBytes[17] = 0x04; // mov dword ptr [edi+4], ebx + codeBytes[18] = 0x89; codeBytes[19] = 0x4F; codeBytes[20] = 0x08; // mov dword ptr [edi+8], ecx + codeBytes[21] = 0x89; codeBytes[22] = 0x57; codeBytes[23] = 0x0C; // mov dword ptr [edi+12],edx + codeBytes[24] = 0x5F; // pop edi + codeBytes[25] = 0x5B; // pop ebx + codeBytes[26] = 0x8B; codeBytes[27] = 0xE5; // mov esp,ebp + codeBytes[28] = 0x5D; // pop ebp + codeBytes[29] = 0xc3; // ret + } else + { + codeBytes = new byte[26]; + codeBytes[0] = 0x53; // push rbx this gets clobbered by cpuid + codeBytes[1] = 0x49; codeBytes[2] = 0x89; codeBytes[3] = 0xd0; // mov r8, rdx + codeBytes[4] = 0x89; codeBytes[5] = 0xc8; // mov eax, ecx + codeBytes[6] = 0x0F; codeBytes[7] = 0xA2; // cpuid + codeBytes[8] = 0x41; codeBytes[9] = 0x89; codeBytes[10] = 0x40; codeBytes[11] = 0x00; // mov dword ptr [r8+0], eax + codeBytes[12] = 0x41; codeBytes[13] = 0x89; codeBytes[14] = 0x58; codeBytes[15] = 0x04; // mov dword ptr [r8+4], ebx + codeBytes[16] = 0x41; codeBytes[17] = 0x89; codeBytes[18] = 0x48; codeBytes[19] = 0x08; // mov dword ptr [r8+8], ecx + codeBytes[20] = 0x41; codeBytes[21] = 0x89; codeBytes[22] = 0x50; codeBytes[23] = 0x0c; // mov dword ptr [r8+12], edx + codeBytes[24] = 0x5b; // pop rbx + codeBytes[25] = 0xc3; // ret + } + + codePointer = Win32.VirtualAlloc( + IntPtr.Zero, + new UIntPtr((uint)codeBytes.Length), + Win32.AllocationType.Commit | Win32.AllocationType.Reserve, + Win32.MemoryProtection.ExecuteReadWrite + ); + + Marshal.Copy(codeBytes, 0, codePointer, codeBytes.Length); + + var cpuIdDelg = (CpuIdDelegate)Marshal.GetDelegateForFunctionPointer(codePointer, typeof(CpuIdDelegate)); + + // invoke + var buffer = new int[4]; + var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); + try + { + cpuIdDelg(level, buffer); + } + finally + { + handle.Free(); + } + + return buffer; + } + finally + { + if (codePointer != IntPtr.Zero) + { + Win32.VirtualFree(codePointer, UIntPtr.Zero, Win32.FreeType.Release); + } + } + } + + [UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + private delegate void CpuIdDelegate(int level, int []buffer); + } +}
\ No newline at end of file diff --git a/runtime/VMProtect.Runtime/Crypto.cs b/runtime/VMProtect.Runtime/Crypto.cs new file mode 100644 index 0000000..729c49f --- /dev/null +++ b/runtime/VMProtect.Runtime/Crypto.cs @@ -0,0 +1,195 @@ +using System; +using System.Runtime.InteropServices; + +// ReSharper disable once CheckNamespace +namespace VMProtect +{ + public class CipherRC5 + { + private const int R = 15; // number of rounds + private const int B = 8; // number of bytes in key + private const int C = 8 * B / BitRotate.W; // 16 - number u32s in key = ceil(8*B/W) + private const int T = 2 * (R + 1); // 34 - size of table _s = 2*(R+1) u32s + + private readonly uint[] _s; // expanded key table + +#if RUNTIME + private const uint P = (uint)Faces.RC5_P; + private const uint Q = (uint)Faces.RC5_Q; +#else + private static readonly uint P = Core.Instance.Rand32(); + private static readonly uint Q = Core.Instance.Rand32(); + + public static byte[] CreateRandomKey() + { + var ret = new byte[B]; + Core.Instance.RndGenerator.NextBytes(ret); + return ret; + } +#endif + + public CipherRC5(byte[] key) + { + uint i, j, k, u = BitRotate.W / 8, a, b; + var l = new uint[C]; + _s = new uint[T]; + + for (i = B - 1, l[C - 1] = 0; i != uint.MaxValue; i--) + l[i / u] = (l[i / u] << 8) + key[i]; + + for (_s[0] = P, i = 1; i < T; i++) + _s[i] = _s[i - 1] + Q; + for (a = b = i = j = k = 0; k < 3 * T; k++, i = (i + 1) % T, j = (j + 1) % C) // 3*T > 3*C + { + a = _s[i] = BitRotate.Left(_s[i] + a + b, 3); + b = l[j] = BitRotate.Left(l[j] + a + b, (int)(a + b)); + } + } + + [StructLayout(LayoutKind.Explicit)] + private struct Dword + { + [FieldOffset(0)] + public ulong dw; + + [FieldOffset(0)] + public uint w0; + + [FieldOffset(4)] + public uint w1; + } + + private void Encrypt(ref Dword io) + { + uint i, a = io.w0 + _s[0], b = io.w1 + _s[1]; + for (i = 1; i <= R; i++) + { + a = BitRotate.Left(a ^ b, (int)b) + _s[2 * i]; + b = BitRotate.Left(b ^ a, (int)a) + _s[2 * i + 1]; + } + io.w0 = a; + io.w1 = b; + } + + private void Decrypt(ref Dword io) + { + uint i, b = io.w1, a = io.w0; + for (i = R; i > 0; i--) + { + b = BitRotate.Right(b - _s[2 * i + 1], (int)a) ^ a; + a = BitRotate.Right(a - _s[2 * i], (int)b) ^ b; + } + io.w1 = b - _s[1]; + io.w0 = a - _s[0]; + } + + public byte[] Encrypt(byte[] ain) + { + var aout = new byte[ain.Length]; + Encrypt(ain, aout); + return aout; + } + + public byte[] Decrypt(byte[] ain) + { + var aout = new byte[ain.Length]; + Decrypt(ain, aout); + return aout; + } + + public void Encrypt(byte[] ain, byte[] aout) + { + var block = new Dword(); + for (var i = 0; i < ain.Length; i += 8) + { + block.dw = BitConverter.ToUInt64(ain, i); + Encrypt(ref block); + BitConverter.GetBytes(block.dw).CopyTo(aout, i); + } + } + + public void Decrypt(byte[] ain, byte[] aout) + { + var block = new Dword(); + for (var i = 0; i < ain.Length; i += 8) + { + block.dw = BitConverter.ToUInt64(ain, i); + Decrypt(ref block); + BitConverter.GetBytes(block.dw).CopyTo(aout, i); + } + } + } + + public class CRC32 + { + static uint[] _table; + + public CRC32() + { + if (_table == null) + { + _table = new uint[256]; + for (var i = 0; i < 256; i++) + { + var entry = (uint)i; + for (var j = 0; j < 8; j++) + if ((entry & 1) == 1) + entry = (entry >> 1) ^ 0xedb88320u; + else + entry = entry >> 1; + _table[i] = entry; + } + } + } + + public uint Hash(IntPtr ptr, uint size) + { + uint crc = 0; + for (var i = 0; i < size; i++) + crc = _table[(Marshal.ReadByte(new IntPtr(ptr.ToInt64() + i)) ^ crc) & 0xff] ^ (crc >> 8); + return ~crc; + } + } + + public class CRCValueCryptor + { + private uint _key; + public CRCValueCryptor() + { + _key = (uint)Faces.CRC_INFO_SALT; + } + + public uint Decrypt(uint value) + { + uint res = value ^ _key; + _key = BitRotate.Left(_key, 7) ^ res; + return res; + } + } + + public class BitRotate + { + public const int W = 32; // u32 size in bits + public static uint Left(uint a, int offset) + { + var r1 = a << offset; + var r2 = a >> (W - offset); + return r1 | r2; + } + + public static uint Right(uint a, int offset) + { + var r1 = a >> offset; + var r2 = a << (W - offset); + return r1 | r2; + } + + public static uint Swap(uint value) + { + uint mask_xx_zz = (value & 0x00FF00FFU); + uint mask_ww_yy = (value & 0xFF00FF00U); + return ((mask_xx_zz >> 8) | (mask_xx_zz << 24)) + + ((mask_ww_yy << 8) | (mask_ww_yy >> 24)); + } + } +}
\ No newline at end of file diff --git a/runtime/VMProtect.Runtime/Faces.cs b/runtime/VMProtect.Runtime/Faces.cs new file mode 100644 index 0000000..c3818e5 --- /dev/null +++ b/runtime/VMProtect.Runtime/Faces.cs @@ -0,0 +1,170 @@ +using System; + +// ReSharper disable once CheckNamespace +// ReSharper disable InconsistentNaming +namespace VMProtect +{ + [AttributeUsage(AttributeTargets.Enum)] + public sealed class DeleteOnCompilation : Attribute { } + + [VMProtect.DeleteOnCompilation] + public enum Variables : uint + { + IS_PATCH_DETECTED, + IS_DEBUGGER_DETECTED, + LOADER_CRC_INFO, + LOADER_CRC_INFO_SIZE, + LOADER_CRC_INFO_HASH, + SESSION_KEY, + DRIVER_UNLOAD, + CRC_IMAGE_SIZE, + LOADER_STATUS, + SERVER_DATE, + RESERVED, + CPU_COUNT, + CPU_HASH, + COUNT = CPU_HASH + 32 + } + + [VMProtect.DeleteOnCompilation] + public enum Faces : uint + { + MASK = 0xFACE0000U, + + RC5_P, + RC5_Q, + + STRING_INFO, + RESOURCE_INFO, + STORAGE_INFO, + REGISTRY_INFO, + LICENSE_INFO, + LICENSE_INFO_SIZE, + KEY_INFO, + RUNTIME_ENTRY, + CRC_INFO_SALT, + CRC_TABLE_ENTRY, + CRC_TABLE_SIZE, + CRC_TABLE_HASH, + TRIAL_HWID, + TRIAL_HWID_SIZE, + CORE_OPTIONS, + IMAGE_BASE, + FILE_BASE, + + NTOSKRNL_NAME, + HAL_NAME, + USER32_NAME, + MESSAGE_BOX_NAME, + KERNEL32_NAME, + CREATE_FILE_NAME, + CLOSE_HANDLE_NAME, + INITIALIZATION_ERROR, + PROC_NOT_FOUND, + ORDINAL_NOT_FOUND, + STRING_DECRYPT_KEY, + DRIVER_FORMAT_VALUE, + FILE_CORRUPTED, + LOADER_OPTIONS, + LOADER_DATA, + DEBUGGER_FOUND, + NT_SET_INFORMATION_PROCESS_NAME, + NT_RAISE_HARD_ERROR_NAME, + IS_WOW64_PROCESS_NAME, + WINE_GET_VERSION_NAME, + MACOSX_FORMAT_VALUE, + GNU_PTRACE, + UNREGISTERED_VERSION, + WTSAPI32_NAME, + WTS_SEND_MESSAGE_NAME, + NTDLL_NAME, + NT_QUERY_INFORMATION_NAME, + NT_SET_INFORMATION_THREAD_NAME, + SICE_NAME, + SIWVID_NAME, + NTICE_NAME, + ICEEXT_NAME, + SYSER_NAME, + VIRTUAL_MACHINE_FOUND, + SBIEDLL_NAME, + QUERY_VIRTUAL_MEMORY_NAME, + ENUM_SYSTEM_FIRMWARE_NAME, + GET_SYSTEM_FIRMWARE_NAME, + NT_QUERY_INFORMATION_PROCESS_NAME, + NT_VIRTUAL_PROTECT_NAME, + NT_OPEN_FILE_NAME, + NT_CREATE_SECTION_NAME, + NT_OPEN_SECTION_NAME, + NT_MAP_VIEW_OF_SECTION, + NT_UNMAP_VIEW_OF_SECTION, + NT_CLOSE, + SYSCALL, + NT_ALLOCATE_VIRTUAL_MEMORY_NAME, + NT_FREE_VIRTUAL_MEMORY_NAME, + + PACKER_INFO = 0xFACE0100U, + PACKER_INFO_SIZE, + FILE_CRC_INFO, + FILE_CRC_INFO_SIZE, + LOADER_CRC_INFO, + LOADER_CRC_INFO_SIZE, + SECTION_INFO, + SECTION_INFO_SIZE, + FIXUP_INFO, + FIXUP_INFO_SIZE, + RELOCATION_INFO, + RELOCATION_INFO_SIZE, + IAT_INFO, + IAT_INFO_SIZE, + IMPORT_INFO, + IMPORT_INFO_SIZE, + INTERNAL_IMPORT_INFO, + INTERNAL_IMPORT_INFO_SIZE, + MEMORY_CRC_INFO, + MEMORY_CRC_INFO_SIZE, + DELAY_IMPORT_INFO, + DELAY_IMPORT_INFO_SIZE, + LOADER_CRC_INFO_HASH, + MEMORY_CRC_INFO_HASH, + TLS_INDEX_INFO, + + VAR = 0xFACE0200U, + VAR_IS_PATCH_DETECTED = VAR | (Variables.IS_PATCH_DETECTED << 4), + VAR_IS_DEBUGGER_DETECTED = VAR | (Variables.IS_DEBUGGER_DETECTED << 4), + VAR_LOADER_CRC_INFO = VAR | (Variables.LOADER_CRC_INFO << 4), + VAR_LOADER_CRC_INFO_SIZE = VAR | (Variables.LOADER_CRC_INFO_SIZE << 4), + VAR_LOADER_CRC_INFO_HASH = VAR | (Variables.LOADER_CRC_INFO_HASH << 4), + VAR_SESSION_KEY = VAR | (Variables.SESSION_KEY << 4), + VAR_LOADER_STATUS = VAR | (Variables.LOADER_STATUS << 4), + VAR_SERVER_DATE = VAR | (Variables.SERVER_DATE << 4), + + VAR_SALT = 0xFACE0300U, + VAR_IS_PATCH_DETECTED_SALT = VAR_SALT | Variables.IS_PATCH_DETECTED, + VAR_IS_DEBUGGER_DETECTED_SALT = VAR_SALT | Variables.IS_DEBUGGER_DETECTED, + VAR_LOADER_CRC_INFO_SALT = VAR_SALT | Variables.LOADER_CRC_INFO, + VAR_LOADER_CRC_INFO_SIZE_SALT = VAR_SALT | Variables.LOADER_CRC_INFO_SIZE, + VAR_LOADER_CRC_INFO_HASH_SALT = VAR_SALT | Variables.LOADER_CRC_INFO_HASH, + VAR_SERVER_DATE_SALT = VAR_SALT | Variables.SERVER_DATE, + } + + public static class GlobalData + { + private static uint[] _v = new uint[(uint)Variables.COUNT]; + public static bool IsPatchDetected() { return (_v[(uint)Faces.VAR_IS_PATCH_DETECTED] ^ (uint)Faces.VAR_IS_PATCH_DETECTED_SALT) != 0; } + public static bool IsDebuggerDetected() { return (_v[(uint)Faces.VAR_IS_DEBUGGER_DETECTED] ^ (uint)Faces.VAR_IS_DEBUGGER_DETECTED_SALT) != 0; } + public static uint LoaderCrcInfo() { return _v[(uint)Faces.VAR_LOADER_CRC_INFO] ^ (uint)Faces.VAR_LOADER_CRC_INFO_SALT; } + public static uint LoaderCrcSize() { return _v[(uint)Faces.VAR_LOADER_CRC_INFO_SIZE] ^ (uint)Faces.VAR_LOADER_CRC_INFO_SIZE_SALT; } + public static uint LoaderCrcHash() { return _v[(uint)Faces.VAR_LOADER_CRC_INFO_HASH] ^ (uint)Faces.VAR_LOADER_CRC_INFO_HASH_SALT; } + public static uint SessionKey() { return _v[(uint)Faces.VAR_SESSION_KEY]; } + public static uint LoaderStatus() { return _v[(uint)Faces.VAR_LOADER_STATUS]; } + public static uint ServerDate() { return _v[(uint)Faces.VAR_SERVER_DATE] ^ (uint)Faces.VAR_SERVER_DATE_SALT; } + public static void SetIsPatchDetected(bool value) { _v[(uint)Faces.VAR_IS_PATCH_DETECTED] = (uint)(value ? 1 : 0) ^ (uint)Faces.VAR_IS_PATCH_DETECTED_SALT; } + public static void SetIsDebuggerDetected(bool value) { _v[(uint)Faces.VAR_IS_DEBUGGER_DETECTED] = (uint)(value ? 1 : 0) ^ (uint)Faces.VAR_IS_DEBUGGER_DETECTED_SALT; } + public static void SetLoaderCrcInfo(uint value) { _v[(uint)Faces.VAR_LOADER_CRC_INFO] = value ^ (uint)Faces.VAR_LOADER_CRC_INFO_SALT; } + public static void SetLoaderCrcSize(uint value) { _v[(uint)Faces.VAR_LOADER_CRC_INFO_SIZE] = value ^ (uint)Faces.VAR_LOADER_CRC_INFO_SIZE_SALT; } + public static void SetLoaderCrcHash(uint value) { _v[(uint)Faces.VAR_LOADER_CRC_INFO_HASH] = value ^ (uint)Faces.VAR_LOADER_CRC_INFO_HASH_SALT; } + public static void SetSessionKey(uint value) { _v[(uint)Faces.VAR_SESSION_KEY] = value; } + public static void SetLoaderStatus(uint value) { _v[(uint)Faces.VAR_LOADER_STATUS] = value; } + public static void SetServerDate(uint value) { _v[(uint)Faces.VAR_SERVER_DATE] = value ^ (uint)Faces.VAR_SERVER_DATE_SALT; } + } +}
\ No newline at end of file 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 diff --git a/runtime/VMProtect.Runtime/LicensingManager.cs b/runtime/VMProtect.Runtime/LicensingManager.cs new file mode 100644 index 0000000..d6d30c2 --- /dev/null +++ b/runtime/VMProtect.Runtime/LicensingManager.cs @@ -0,0 +1,664 @@ +using System; +using System.Globalization; +using System.Net; +using System.Net.Cache; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Text; +using Numerics; + +// ReSharper disable once CheckNamespace +namespace VMProtect +{ + public class LicensingManager + { + public class BaseRequest + { + protected bool BuildUrl(byte[] licenseData) + { + var urlSize = BitConverter.ToInt32(licenseData, (int)Fields.ActivationUrlSize * sizeof(uint)); + if (urlSize == 0) + return false; + + var urlOffset = BitConverter.ToInt32(licenseData, (int)Fields.ActivationUrlOffset * sizeof(uint)); + Url = Encoding.UTF8.GetString(licenseData, urlOffset, urlSize); + if (Url[Url.Length - 1] != '/') + Url += '/'; + return true; + } + protected void EncodeUrl() + { + Url = Convert.ToBase64String(Encoding.UTF8.GetBytes(Url)); + } + protected void AppendUrlParam(string param, string value) + { + AppendUrl(param, false); + AppendUrl(value, true); + } + private void AppendUrl(string str, bool escape) + { + if (escape) + { + var sb = new StringBuilder(Url); + foreach (var c in str) + { + switch (c) + { + case '+': + sb.Append("%2B"); + break; + case '/': + sb.Append("%2F"); + break; + case '=': + sb.Append("%3D"); + break; + default: + sb.Append(c); + break; + } + } + Url = sb.ToString(); + } else + { + Url += str; + } + } + + public bool Send() + { + try + { + using (var wc = new WebClient()) + { + ServicePointManager.ServerCertificateValidationCallback += + (sender, certificate, chain, sslPolicyErrors) => true; + wc.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore); + wc.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"); + Response = wc.DownloadString(Url); + try + { + var strDt = wc.ResponseHeaders.Get("Date"); + var dt = DateTime.ParseExact(strDt, "ddd, dd MMM yyyy HH:mm:ss 'GMT'", + CultureInfo.InvariantCulture.DateTimeFormat, DateTimeStyles.AssumeUniversal); + GlobalData.SetServerDate((uint)((dt.Year << 16) + (dt.Month << 8) + dt.Day)); + } + catch (Exception) + { + //не смогли вытащить дату из заголовков - прощаем? + } + return true; + } + } + catch (Exception) + { + return false; + } + } + + public string Url { get; private set; } + public string Response { get; private set; } + } + + public class ActivationRequest : BaseRequest + { + public ActivationStatus Process(byte[] licenseData, string code, bool offline) + { + if (!VerifyCode(code)) + return ActivationStatus.BadCode; + + if (!BuildUrl(licenseData, code, offline)) + return ActivationStatus.NotAvailable; + + if (offline) + return ActivationStatus.Ok; + + if (!Send()) + return ActivationStatus.NoConnection; + + var res = Response; + if (string.IsNullOrEmpty(res)) + return ActivationStatus.BadReply; + + // possible answers: OK, BAD, BANNED, USED, EXPIRED + // if OK - see the Serial number below + + if (res == "BAD") + return ActivationStatus.BadCode; + + if (res == "BANNED") + return ActivationStatus.Banned; + + if (res == "USED") + return ActivationStatus.AlreadyUsed; + + if (res == "EXPIRED") + return ActivationStatus.Expired; + + var crPos = res.IndexOf('\n'); + if (crPos != 2) + return ActivationStatus.BadReply; + + if (res[0] != 'O' || res[1] != 'K') + return ActivationStatus.BadReply; + + if (res.Length - 3 < 64) + return ActivationStatus.BadReply; + + Serial = res.Substring(3); + return ActivationStatus.Ok; + } + public string Serial + { + get; private set; + } + private bool VerifyCode(string code) + { + if (string.IsNullOrEmpty(code) || code.Length > 32) + return false; + return code.ToLower().TrimEnd("0123456789abcdefghijklmnopqrstuvwxyz-".ToCharArray()).Length == 0; + } + private bool BuildUrl(byte[] licenseData, string code, bool offline) + { + if (!offline) { + if (!base.BuildUrl(licenseData)) + return false; + } + + // hwid -> base64 + var hwid = Convert.ToBase64String(Core.Instance.HWID.GetBytes()); + + // hash -> base64 + var modSize = BitConverter.ToInt32(licenseData, (int)Fields.ModulusSize * sizeof(uint)); + var modOffset = BitConverter.ToInt32(licenseData, (int)Fields.ModulusOffset * sizeof(uint)); + using (var sha = new SHA1Managed()) + { + var modulus = sha.ComputeHash(licenseData, modOffset, modSize); + var hash = Convert.ToBase64String(modulus, 0, 20); + + // build Url + AppendUrlParam(offline ? "type=activation&code=" : "activation.php?code=", code); + AppendUrlParam("&hwid=", hwid); + AppendUrlParam("&hash=", hash); + } + + if (offline) + EncodeUrl(); + + return true; + } + } + + public class DeactivationRequest : BaseRequest + { + public ActivationStatus Process(byte[] licenseData, string serial, bool offline) + { + if (!VerifySerial(serial)) + return ActivationStatus.BadCode; + + if (!BuildUrl(licenseData, serial, offline)) + return ActivationStatus.NotAvailable; + + if (offline) + return ActivationStatus.Ok; + + if (!Send()) + return ActivationStatus.NoConnection; + + var res = Response; + if (string.IsNullOrEmpty(res)) + return ActivationStatus.BadReply; + + if (res == "OK") + return ActivationStatus.Ok; + + if (res == "ERROR") + return ActivationStatus.Corrupted; + + if (res == "UNKNOWN") + return ActivationStatus.SerialUnknown; + + return ActivationStatus.BadReply; + } + + private bool VerifySerial(string serial) + { + return !string.IsNullOrEmpty(serial); + } + + private bool BuildUrl(byte[] licenseData, string serial, bool offline) + { + if (!offline) { + if (!base.BuildUrl(licenseData)) + return false; + } + + try + { + var serialBytes = Convert.FromBase64String(serial); + using (var sha = new SHA1Managed()) + { + var serialHash = sha.ComputeHash(serialBytes); + var hash = Convert.ToBase64String(serialHash, 0, 20); + + AppendUrlParam(offline ? "type=deactivation&hash=" : "deactivation.php?hash=", hash); + } + } + catch (FormatException) + { + return false; + } + + if (offline) + EncodeUrl(); + + return true; + } + } + public LicensingManager(long instance) + { + _sessionKey = 0 - GlobalData.SessionKey(); + _licenseData = new byte[(uint)Faces.LICENSE_INFO_SIZE]; + Marshal.Copy(new IntPtr(instance + (uint)Faces.LICENSE_INFO), _licenseData, 0, _licenseData.Length); + _startTickCount = Environment.TickCount; + } + public LicensingManager(byte [] licenseData) + { + _licenseData = licenseData; + } + public SerialState GetSerialNumberState() + { + lock (_lock) + { + return (_state & (SerialState.Corrupted | SerialState.Invalid | SerialState.BadHwid | SerialState.Blacklisted)) != 0 ? _state : ParseSerial(null); + } + } + public ActivationStatus ActivateLicense(string code, out string serial) + { + serial = string.Empty; + if (!CheckLicenseDataCRC()) + return ActivationStatus.Corrupted; + + var request = new ActivationRequest(); + var res = request.Process(_licenseData, code, false); + if (res == ActivationStatus.Ok) + { + serial = request.Serial; + } + return res; + } + + public ActivationStatus DeactivateLicense(string serial) + { + return CheckLicenseDataCRC() ? + new DeactivationRequest().Process(_licenseData, serial, false) : + ActivationStatus.Corrupted; + } + + public ActivationStatus GetOfflineActivationString(string code, out string buf) + { + buf = string.Empty; + if (!CheckLicenseDataCRC()) + return ActivationStatus.Corrupted; + + var request = new ActivationRequest(); + var res = request.Process(_licenseData, code, true); + if (res == ActivationStatus.Ok) + { + buf = request.Url; + } + return res; + } + + public ActivationStatus GetOfflineDeactivationString(string serial, out string buf) + { + buf = string.Empty; + if (!CheckLicenseDataCRC()) + return ActivationStatus.Corrupted; + + var request = new DeactivationRequest(); + var res = request.Process(_licenseData, serial, true); + if (res == ActivationStatus.Ok) + { + buf = request.Url; + } + return res; + } + + private static BigInteger B2Bi(byte[] b) //reverse & make positive + { + Array.Reverse(b); + var b2 = new byte[b.Length + 1]; + Array.Copy(b, b2, b.Length); + return new BigInteger(b2); + } + + public SerialState SetSerialNumber(string serial) + { + lock (_lock) + { + SaveState(SerialState.Invalid); + + if (string.IsNullOrEmpty(serial)) + return SerialState.Invalid; // the key is empty + + // decode serial number from base64 + byte[] binarySerial; + try + { + binarySerial = Convert.FromBase64String(serial); + if (binarySerial.Length < 16) + return SerialState.Invalid; + } + catch (Exception) + { + return SerialState.Invalid; + } + + // check license data integrity + if (!CheckLicenseDataCRC()) { + return SaveState(SerialState.Corrupted); + } + + // check serial by black list + var blackListSize = BitConverter.ToInt32(_licenseData, (int)Fields.BlacklistSize * sizeof(uint)); + if (blackListSize != 0) { + var blackListOffset = BitConverter.ToInt32(_licenseData, (int)Fields.BlacklistOffset * sizeof(uint)); + + using (var hash = new SHA1Managed()) + { + var p = hash.ComputeHash(binarySerial); + int min = 0; + int max = blackListSize / 20 - 1; + while (min <= max) + { + int i = (min + max) / 2; + var blocked = true; + for (var j = 0; j < 20 / sizeof(uint); j++) { + var dw = BitConverter.ToUInt32(_licenseData, blackListOffset + i * 20 + j * sizeof(uint)); + var v = BitConverter.ToUInt32(p, j * sizeof(uint)); + if (dw == v) + continue; + + if (BitRotate.Swap(dw) > BitRotate.Swap(v)) + { + max = i - 1; + } + else + { + min = i + 1; + } + blocked = false; + break; + } + if (blocked) { + return SaveState(SerialState.Blacklisted); + } + } + } + } + + // decode serial number + var ebytes = new byte[BitConverter.ToInt32(_licenseData, (int)Fields.PublicExpSize * sizeof(uint))]; + Array.Copy(_licenseData, BitConverter.ToInt32(_licenseData, (int)Fields.PublicExpOffset * sizeof(uint)), ebytes, 0, ebytes.Length); + var e = B2Bi(ebytes); + var nbytes = new byte[BitConverter.ToInt32(_licenseData, (int)Fields.ModulusSize * sizeof(uint))]; + Array.Copy(_licenseData, BitConverter.ToInt32(_licenseData, (int)Fields.ModulusOffset * sizeof(uint)), nbytes, 0, nbytes.Length); + var n = B2Bi(nbytes); + var x = B2Bi(binarySerial); + + if (n < x) { + // data is too long to crypt + return SerialState.Invalid; + } + + _serial = BigInteger.ModPow(x, e, n).ToByteArray(); + Array.Reverse(_serial); + + if (_serial[0] != 0 || _serial[1] != 2) + return SerialState.Invalid; + + int pos; + for (pos = 2; pos < _serial.Length; pos++) { + if (_serial[pos] == 0) { + pos++; + break; + } + } + if (pos == _serial.Length) + return SerialState.Invalid; + + _start = pos; + return ParseSerial(null); + } + } + + public bool GetSerialNumberData(SerialNumberData data) + { + lock (_lock) + { + if (_state == SerialState.Corrupted) + return false; + + data.State = (_state & (SerialState.Invalid | SerialState.Blacklisted | SerialState.BadHwid)) != 0 ? _state : ParseSerial(data); + return true; + } + } + + public uint DecryptBuffer(uint p3, uint p2, uint p1, uint p0) + { + uint key0 = (uint)_productCode; + uint key1 = (uint)(_productCode >> 32) + _sessionKey; + + p0 = BitRotate.Left((p0 + _sessionKey) ^ key0, 7) + key1; + p1 = BitRotate.Left((p1 + _sessionKey) ^ key0, 11) + key1; + p2 = BitRotate.Left((p2 + _sessionKey) ^ key0, 17) + key1; + p3 = BitRotate.Left((p3 + _sessionKey) ^ key0, 23) + key1; + + if (p0 + p1 + p2 + p3 != _sessionKey * 4) + { + Core.ShowMessage("This code requires valid serial number to run.\nProgram will be terminated."); + Environment.Exit(1); + } + + return p3; + } + + [VMProtect.DeleteOnCompilation] + private enum ChunkType + { + Version = 0x01, // 1 byte of data - version + UserName = 0x02, // 1 + N bytes - length + N bytes of customer's name (without enging \0). + Email = 0x03, // 1 + N bytes - length + N bytes of customer's email (without ending \0). + HWID = 0x04, // 1 + N bytes - length + N bytes of hardware id (N % 4 == 0) + ExpDate = 0x05, // 4 bytes - (year << 16) + (month << 8) + (day) + RunningTimeLimit = 0x06, // 1 byte - number of minutes + ProductCode = 0x07, // 8 bytes - used for decrypting some parts of exe-file + UserData = 0x08, // 1 + N bytes - length + N bytes of user data + MaxBuild = 0x09, // 4 bytes - (year << 16) + (month << 8) + (day) + End = 0xFF // 4 bytes - checksum: the first four bytes of sha-1 hash from the data before that chunk + } + + private SerialState SaveState(SerialState state) + { + _state = state; + if ((_state & (SerialState.Invalid | SerialState.BadHwid)) != 0) + { + _serial = null; + _productCode = 0; + } + return _state; + } + private SerialState ParseSerial(SerialNumberData data) + { + if (_serial == null) + return SerialState.Invalid; + + var newState = _state & (SerialState.MaxBuildExpired | SerialState.DateExpired | SerialState.RunningTimeOver); + var pos = _start; + while (pos < _serial.Length) { + var b = _serial[pos++]; + byte s; + switch (b) { + case (byte)ChunkType.Version: + if (_serial[pos] != 1) + return SaveState(SerialState.Invalid); + pos += 1; + break; + case (byte)ChunkType.ExpDate: + var expDate = BitConverter.ToUInt32(_serial, pos); + if ((newState & SerialState.DateExpired) == 0) { + if (BitConverter.ToUInt32(_licenseData, (int)Fields.BuildDate * sizeof(uint)) > expDate || GetCurrentDate() > expDate) + newState |= SerialState.DateExpired; + } + if (data != null) { + data.Expires = new DateTime((int)(expDate >> 16), (byte)(expDate >> 8), (byte)expDate); + } + pos += 4; + break; + case (byte)ChunkType.RunningTimeLimit: + s = _serial[pos]; + if ((newState & SerialState.RunningTimeOver) == 0) { + var curTime = (Environment.TickCount - _startTickCount) / 1000 / 60; + if (curTime > s) + newState |= SerialState.RunningTimeOver; + } + if (data != null) + data.RunningTime = s; + pos += 1; + break; + case (byte)ChunkType.ProductCode: + if ((_state & SerialState.Invalid) != 0) + _productCode = BitConverter.ToInt64(_serial, pos); + pos += 8; + break; + case (byte)ChunkType.MaxBuild: + var maxBuildDate = BitConverter.ToUInt32(_serial, pos); + if ((newState & SerialState.MaxBuildExpired) == 0) { + if (BitConverter.ToUInt32(_licenseData, (int)Fields.BuildDate * sizeof(uint)) > maxBuildDate) + newState |= SerialState.MaxBuildExpired; + } + if (data != null) + { + data.MaxBuild = new DateTime((int)(maxBuildDate >> 16), (byte)(maxBuildDate >> 8), (byte)maxBuildDate); + } + pos += 4; + break; + case (byte)ChunkType.UserName: + s = _serial[pos++]; + if (data != null) + data.UserName = Encoding.UTF8.GetString(_serial, pos, s); + pos += s; + break; + case (byte)ChunkType.Email: + s = _serial[pos++]; + if (data != null) + data.EMail = Encoding.UTF8.GetString(_serial, pos, s); + pos += s; + break; + case (byte)ChunkType.HWID: + s = _serial[pos++]; + if ((_state & SerialState.Invalid) != 0) + { + var shwid = new byte[s]; + Array.Copy(_serial, pos, shwid, 0, s); + if (!Core.Instance.HWID.IsCorrect(shwid)) + return SaveState(SerialState.BadHwid); + } + pos += s; + break; + case (byte)ChunkType.UserData: + s = _serial[pos++]; + if (data != null) { + data.UserData = new byte[s]; + for (var i = 0; i < s; i++) { + data.UserData[i] = _serial[pos + i]; + } + } + pos += s; + break; + case (byte)ChunkType.End: + if (pos + 4 > _serial.Length) + return SaveState(SerialState.Invalid); + + if ((_state & SerialState.Invalid) != 0) { + // calc hash without last chunk + using (var hash = new SHA1Managed()) + { + var p = hash.ComputeHash(_serial, _start, pos - _start - 1); + + // check CRC + for (var i = 0; i < 4; i++) { + if (_serial[pos + i] != p[3 - i]) + return SaveState(SerialState.Invalid); + } + } + } + + return SaveState(newState); + } + } + + // SERIAL_CHUNK_END not found + return SaveState(SerialState.Invalid); + } + + [VMProtect.DeleteOnCompilation] + internal enum Fields + { + BuildDate, + PublicExpOffset, + PublicExpSize, + ModulusOffset, + ModulusSize, + BlacklistOffset, + BlacklistSize, + ActivationUrlOffset, + ActivationUrlSize, + CRCOffset, + Count + } + private bool CheckLicenseDataCRC() + { + var crcPos = BitConverter.ToInt32(_licenseData, (int)Fields.CRCOffset * sizeof(uint)); + var size = crcPos + 16; + if (size != _licenseData.Length) + return false; // bad key size + + // CRC check + using (var hash = new SHA1Managed()) + { + var h = hash.ComputeHash(_licenseData, 0, crcPos); + for (var i = crcPos; i < size; i++) + { + if (_licenseData[i] != h[i - crcPos]) + return false; + } + } + + return true; + } + + internal static uint GetCurrentDate() + { + var dt = DateTime.Now; + var curDate = (uint)((dt.Year << 16) + (dt.Month << 8) + dt.Day); + var serverDate = GlobalData.ServerDate(); + return serverDate > curDate ? serverDate : curDate; + } + + private readonly byte[] _licenseData; + private byte[] _serial; + private readonly object _lock = new object(); + private SerialState _state = SerialState.Invalid; + //TODO + //ReSharper disable once NotAccessedField.Local + private long _productCode; + private readonly int _startTickCount; + private int _start; + private uint _sessionKey; + /* + CryptoContainer *_serial; + */ + } +}
\ No newline at end of file diff --git a/runtime/VMProtect.Runtime/Loader.cs b/runtime/VMProtect.Runtime/Loader.cs new file mode 100644 index 0000000..8511045 --- /dev/null +++ b/runtime/VMProtect.Runtime/Loader.cs @@ -0,0 +1,703 @@ +using System; +using System.IO; +using System.Text; +using System.Runtime.InteropServices; +using System.Reflection; +using System.Diagnostics; +using System.Reflection.Emit; + +// ReSharper disable once CheckNamespace +namespace VMProtect +{ + [VMProtect.DeleteOnCompilation] + enum MessageType + { + InitializationError, + ProcNotFound, + OrdinalNotFound, + FileCorrupted, + DebuggerFound, + UnregisteredVersion, + VirtualMachineFound + } + + [VMProtect.DeleteOnCompilation] + enum ErrorType + { + VIRTUAL_PROTECT_ERROR = 1, + UNPACKER_ERROR = 2 + } + + [VMProtect.DeleteOnCompilation] + enum LoaderOption + { + CHECK_PATCH = 0x1, + CHECK_DEBUGGER = 0x2, + CHECK_KERNEL_DEBUGGER = 0x4, + EXIT_PROCESS = 0x8, + CHECK_VIRTUAL_MACHINE = 0x10 + } + + [VMProtect.DeleteOnCompilation] + enum FixupType + { + Absolute = 0, + High = 1, + Low = 2, + HighLow = 3, + Dir64 = 10 + } + + public static class Loader + { + public static object[] IAT; + + 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; + } + + private static void ShowMessage(uint type, uint param = 0) + { + uint position; + switch (type) + { + case (uint)MessageType.DebuggerFound: + position = (uint)Faces.DEBUGGER_FOUND; + break; + case (uint)MessageType.VirtualMachineFound: + position = (uint)Faces.VIRTUAL_MACHINE_FOUND; + break; + case (uint)MessageType.FileCorrupted: + position = (uint)Faces.FILE_CORRUPTED; + break; + case (uint)MessageType.UnregisteredVersion: + position = (uint)Faces.UNREGISTERED_VERSION; + break; + case (uint)MessageType.InitializationError: + position = (uint)Faces.INITIALIZATION_ERROR; + break; + default: + return; + } + + long instance = Marshal.GetHINSTANCE(typeof(Loader).Module).ToInt64(); + String message = null; + var buffer = new byte[1024]; + for (var pos = 0; pos < 512; pos++) + { + var c = (ushort)(Marshal.ReadInt16(new IntPtr(instance + position + pos * 2)) ^ (BitRotate.Left((uint)Faces.STRING_DECRYPT_KEY, pos) + pos)); + if (c == 0) + { + if (pos > 0) + message = Encoding.Unicode.GetString(buffer, 0, pos * 2); + break; + } + + buffer[pos * 2] = (byte)c; + buffer[pos * 2 + 1] = (byte)(c >> 8); + } + if (message != null) + { + if (type == (uint)MessageType.InitializationError) + message = String.Format(message, param); + Win32.ShowMessage(message, Assembly.GetExecutingAssembly().GetName().Name, MessageBoxButtons.OK, type == (uint)MessageType.UnregisteredVersion ? MessageBoxIcon.Warning : MessageBoxIcon.Error); + } + } + + internal static bool LzmaDecode(IntPtr dst, IntPtr src, byte[] properties, ref uint dstSize, out uint srcSize) + { + srcSize = 0; + unsafe + { + using ( + var srcStream = new UnmanagedMemoryStream((byte*)src.ToPointer(), int.MaxValue, int.MaxValue, FileAccess.Read) + ) + { + using ( + var dstStream = new UnmanagedMemoryStream((byte*) dst.ToPointer(), dstSize, dstSize, + FileAccess.Write)) + { + try + { + var coder = new SevenZip.Compression.LZMA.Decoder(); + coder.SetDecoderProperties(properties); + coder.Code(srcStream, dstStream, dstSize); + dstStream.Flush(); + + srcSize = (uint)srcStream.Position; + dstSize = (uint)dstStream.Position; + } + catch (Exception) + { + return false; + } + + return true; + } + } + } + } + + public static void Main() + { + if (GlobalData.LoaderStatus() != 0) + return; + + var module = typeof(Loader).Module; + long instance = Marshal.GetHINSTANCE(module).ToInt64(); + var options = (uint)Faces.LOADER_OPTIONS; + GlobalData.SetIsPatchDetected(false); + GlobalData.SetIsDebuggerDetected(false); + GlobalData.SetLoaderCrcInfo((uint)Faces.LOADER_CRC_INFO); + GlobalData.SetLoaderCrcSize((uint)Faces.LOADER_CRC_INFO_SIZE); + GlobalData.SetLoaderCrcHash((uint)Faces.LOADER_CRC_INFO_HASH); + GlobalData.SetServerDate(0); + + // detect a debugger + if ((options & (uint)LoaderOption.CHECK_DEBUGGER) != 0) + { + if (Debugger.IsAttached || Debugger.IsLogging()) + { + ShowMessage((uint)MessageType.DebuggerFound); + Environment.Exit(1); + return; + } + + if (Win32.IsDebuggerPresent() || Win32.CheckRemoteDebuggerPresent()) + { + ShowMessage((uint)MessageType.DebuggerFound); + Environment.Exit(1); + return; + } + + Win32.NtSetInformationThread(Win32.CurrentThread, Win32.THREADINFOCLASS.ThreadHideFromDebugger, IntPtr.Zero, 0); + } + + // check header and loader CRC + var crcSize = (uint)Faces.LOADER_CRC_INFO_SIZE; + if (crcSize != 0) + { + crcSize = (uint)Marshal.ReadInt32(new IntPtr(instance + crcSize)); + var crcPosition = (uint)Faces.LOADER_CRC_INFO; + var crcCryptor = new CRCValueCryptor(); + bool isValid = true; + var crcInfo = new byte[12]; + var crc32 = new CRC32(); + var crcHash = (uint)Marshal.ReadInt32(new IntPtr(instance + (uint)Faces.LOADER_CRC_INFO_HASH)); + if (crcHash != crc32.Hash(new IntPtr(instance + crcPosition), crcSize)) + isValid = false; + 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; + } + + if (!isValid) + { + if ((options & (uint)LoaderOption.CHECK_PATCH) != 0) + { + ShowMessage((uint)MessageType.FileCorrupted); + Environment.Exit(1); + return; + } + GlobalData.SetIsPatchDetected(true); + } + } + + // check file CRC + crcSize = (uint)Faces.FILE_CRC_INFO_SIZE; + if (crcSize != 0) //-V3022 + { + crcSize = (uint)Marshal.ReadInt32(new IntPtr(instance + crcSize)); + var crcPosition = (uint)Faces.FILE_CRC_INFO; + bool isValid = true; + var file = Win32.OpenFile(Assembly.GetExecutingAssembly().Location, (uint)Win32.Values.GENERIC_READ, (uint)Win32.Values.FILE_SHARE_READ | (uint)Win32.Values.FILE_SHARE_WRITE); + if (file != Win32.InvalidHandleValue) + { + var fileSize = Win32.GetFileSize(file, IntPtr.Zero); + if (fileSize < (uint)Marshal.ReadInt32(new IntPtr(instance + crcPosition))) + isValid = false; + else + { + var map = Win32.CreateFileMapping(file, IntPtr.Zero, Win32.MemoryProtection.ReadOnly, 0, 0, null); + if (map != Win32.NullHandle) + { + IntPtr baseAddress = Win32.MapViewOfFile(map, Win32.MapAccess.Read, 0, 0, IntPtr.Zero); + if (baseAddress != IntPtr.Zero) + { + var crcInfo = new byte[12]; + var crc32 = new CRC32(); + var crcCryptor = new CRCValueCryptor(); + for (var i = 4; 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(baseAddress.ToInt64() + address), size) != hash) + isValid = false; + } + Win32.UnmapViewOfFile(baseAddress); + } + Win32.CloseHandle(map); + } + } + Win32.CloseHandle(file); + } + + if (!isValid) + { + if ((options & (uint)LoaderOption.CHECK_PATCH) != 0) + { + ShowMessage((uint)MessageType.FileCorrupted); + Environment.Exit(1); + return; + } + GlobalData.SetIsPatchDetected(true); + } + } + + // setup WRITABLE flag for memory pages + var sectionSize = (uint)Faces.SECTION_INFO_SIZE; + if (sectionSize != 0) + { + var sectionPos = (uint)Faces.SECTION_INFO; + var sectionInfo = new byte[12]; + for (var i = 0; i < sectionSize; i += sectionInfo.Length) //-V3022 + { + Marshal.Copy(new IntPtr(instance + sectionPos + i), sectionInfo, 0, sectionInfo.Length); + uint address = BitConverter.ToUInt32(sectionInfo, 0); + uint size = BitConverter.ToUInt32(sectionInfo, 4); + uint type = BitConverter.ToUInt32(sectionInfo, 8); + + Win32.MemoryProtection protect, old_protect; + protect = ((type & (uint)Win32.SectionType.Execute) != 0) ? Win32.MemoryProtection.ExecuteReadWrite : Win32.MemoryProtection.ReadWrite; + if (!Win32.VirtualProtect(new IntPtr(instance + address), new UIntPtr(size), protect, out old_protect)) + { + ShowMessage((uint)MessageType.InitializationError, (uint)ErrorType.VIRTUAL_PROTECT_ERROR); + Environment.Exit(1); + return; + } + if (((uint)old_protect & ((uint)Win32.MemoryProtection.NoAccess | (uint)Win32.MemoryProtection.Guard)) != 0) + { + if ((options & (uint)LoaderOption.CHECK_DEBUGGER) != 0) + { + ShowMessage((uint)MessageType.DebuggerFound); + Environment.Exit(1); + return; + } + GlobalData.SetIsDebuggerDetected(true); + } + } + } + + // unpack regions + var packerSize = (uint)Faces.PACKER_INFO_SIZE; + if (packerSize != 0) + { + int tlsIndex = 0; + var tlsIndexPos = (uint)Faces.TLS_INDEX_INFO; + if (tlsIndexPos != 0) + tlsIndex = Marshal.ReadInt32(new IntPtr(instance + tlsIndexPos)); + + var packerPos = (uint)Faces.PACKER_INFO; + var packerInfo = new byte[8]; + Marshal.Copy(new IntPtr(instance + packerPos), packerInfo, 0, packerInfo.Length); + uint src = BitConverter.ToUInt32(packerInfo, 0); + uint dst = BitConverter.ToUInt32(packerInfo, 4); + var properties = new byte[dst]; + Marshal.Copy(new IntPtr(instance + src), properties, 0, properties.Length); + for (var i = packerInfo.Length; i < packerSize; i += packerInfo.Length) //-V3022 + { + Marshal.Copy(new IntPtr(instance + packerPos + i), packerInfo, 0, packerInfo.Length); + src = BitConverter.ToUInt32(packerInfo, 0); + dst = BitConverter.ToUInt32(packerInfo, 4); + uint dstSize = int.MaxValue, srcSize; + + if (!LzmaDecode(new IntPtr(instance + dst), new IntPtr(instance + src), properties, ref dstSize, out srcSize)) + { + ShowMessage((uint)MessageType.InitializationError, (uint)ErrorType.UNPACKER_ERROR); + Environment.Exit(1); + return; + } + } + + if (tlsIndexPos != 0) + Marshal.WriteInt32(new IntPtr(instance + tlsIndexPos), tlsIndex); + } + + // setup fixups + long fileBase = (uint)Faces.FILE_BASE; + long deltaBase = instance - fileBase; + if (deltaBase != 0) + { + var fixupSize = (uint)Faces.FIXUP_INFO_SIZE; + if (fixupSize != 0) + { + var fixupPos = (uint)Faces.FIXUP_INFO; + var fixupInfo = new byte[8]; + uint blockSize = 0; + for (uint i = 0; i < fixupSize; i += blockSize) + { + Marshal.Copy(new IntPtr(instance + fixupPos + i), fixupInfo, 0, fixupInfo.Length); + uint address = BitConverter.ToUInt32(fixupInfo, 0); + blockSize = BitConverter.ToUInt32(fixupInfo, 4); + if (blockSize < fixupInfo.Length) + break; + + var c = blockSize - fixupInfo.Length; + var block = new byte[c]; + Marshal.Copy(new IntPtr(instance + fixupPos + i + fixupInfo.Length), block, 0, block.Length); + for (var j = 0; j < c; j += 2) + { + ushort typeOffset = BitConverter.ToUInt16(block, j); + var type = (typeOffset & 0xf); + var ptr = new IntPtr(instance + address + (typeOffset >> 4)); + + if (type == (uint)FixupType.HighLow) + { + int value = Marshal.ReadInt32(ptr); + value += (int)deltaBase; + Marshal.WriteInt32(ptr, value); + } + else if (type == (uint)FixupType.Dir64) + { + long value = Marshal.ReadInt64(ptr); + value += deltaBase; + Marshal.WriteInt64(ptr, value); + } + else if (type == (uint)FixupType.High) + { + short value = Marshal.ReadInt16(ptr); + value += (short)(deltaBase >> 16); + Marshal.WriteInt16(ptr, value); + } + else if (type == (uint)FixupType.Low) + { + short value = Marshal.ReadInt16(ptr); + value += (short)deltaBase; + Marshal.WriteInt16(ptr, value); + } + } + } + } + } + + // setup IAT + var iatSize = (uint)Faces.IAT_INFO_SIZE; + if (iatSize != 0) + { + var iatPos = (uint)Faces.IAT_INFO; + var iatInfo = new byte[12]; + for (var i = 0; i < iatSize; i += iatInfo.Length) //-V3022 + { + Marshal.Copy(new IntPtr(instance + iatPos + i), iatInfo, 0, iatInfo.Length); + uint src = BitConverter.ToUInt32(iatInfo, 0); + uint dst = BitConverter.ToUInt32(iatInfo, 4); + uint size = BitConverter.ToUInt32(iatInfo, 8); + + var data = new byte[size]; + Marshal.Copy(new IntPtr(instance + src), data, 0, data.Length); + Marshal.Copy(data, 0, new IntPtr(instance + dst), data.Length); + } + } + + // reset WRITABLE flag for memory pages + if (sectionSize != 0) //-V3022 + { + var sectionPos = (uint)Faces.SECTION_INFO; + var sectionInfo = new byte[12]; + for (var i = 0; i < sectionSize; i += sectionInfo.Length) //-V3022 + { + Marshal.Copy(new IntPtr(instance + sectionPos + i), sectionInfo, 0, sectionInfo.Length); + uint address = BitConverter.ToUInt32(sectionInfo, 0); + uint size = BitConverter.ToUInt32(sectionInfo, 4); + uint type = BitConverter.ToUInt32(sectionInfo, 8); + + Win32.MemoryProtection protect, old_protect; + if ((type & (uint)Win32.SectionType.Read) != 0) + { + if ((type & (uint)Win32.SectionType.Write) != 0) + protect = ((type & (uint)Win32.SectionType.Execute) != 0) ? Win32.MemoryProtection.ExecuteReadWrite : Win32.MemoryProtection.ReadWrite; + else + protect = ((type & (uint)Win32.SectionType.Execute) != 0) ? Win32.MemoryProtection.ExecuteRead : Win32.MemoryProtection.ReadOnly; + } + else + { + protect = ((type & (uint)Win32.SectionType.Execute) != 0) ? Win32.MemoryProtection.Execute : Win32.MemoryProtection.NoAccess; + } + if (!Win32.VirtualProtect(new IntPtr(instance + address), new UIntPtr(size), protect, out old_protect)) + { + ShowMessage((uint)MessageType.InitializationError, (uint)ErrorType.VIRTUAL_PROTECT_ERROR); + Environment.Exit(1); + } + if (((uint)old_protect & ((uint)Win32.MemoryProtection.NoAccess | (uint)Win32.MemoryProtection.Guard)) != 0) + { + if ((options & (uint)LoaderOption.CHECK_DEBUGGER) != 0) + { + ShowMessage((uint)MessageType.DebuggerFound); + Environment.Exit(1); + return; + } + GlobalData.SetIsDebuggerDetected(true); + } + } + } + + // detect a virtual machine + if ((options & (uint)LoaderOption.CHECK_VIRTUAL_MACHINE) != 0) + { + var info = CpuId.Invoke(1); + if (((info[2] >> 31) & 1) != 0) + { + // hypervisor found + bool isFound = true; + // 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) + isFound = false; + } + if (isFound) + { + ShowMessage((uint)MessageType.VirtualMachineFound); + Environment.Exit(1); + return; + } + } + 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)) + { + ShowMessage((uint)MessageType.VirtualMachineFound); + Environment.Exit(1); + return; + } + } + } + } + } + } + + // check memory CRC + crcSize = (uint)Faces.MEMORY_CRC_INFO_SIZE; + if (crcSize != 0) //-V3022 + { + var crcPosition = (uint)Faces.MEMORY_CRC_INFO; + var crcCryptor = new CRCValueCryptor(); + bool isValid = true; + var crcInfo = new byte[12]; + var crc32 = new CRC32(); + var crcHash = (uint)Faces.MEMORY_CRC_INFO_HASH; + if (crcHash != crc32.Hash(new IntPtr(instance + crcPosition), crcSize)) + isValid = false; + for (var i = 0; i < crcSize; i += crcInfo.Length) //-V3022 + { + 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; + } + + if (!isValid) + { + if ((options & (uint)LoaderOption.CHECK_PATCH) != 0) + { + ShowMessage((uint)MessageType.FileCorrupted); + Environment.Exit(1); + return; + } + GlobalData.SetIsPatchDetected(true); + } + } + + GlobalData.SetSessionKey((uint)new Random().Next()); + + if (!Core.Instance.Init(instance)) + { + Environment.Exit(1); + return; + } + + // setup Import + var importSize = (uint)Faces.IMPORT_INFO_SIZE; + if (importSize != 0) + { + var importPos = (uint)Faces.IMPORT_INFO; + var key = (uint)Faces.STRING_DECRYPT_KEY; + var importInfo = new byte[12]; + object[] iat = new object[importSize / importInfo.Length]; + uint index = 0; + for (var i = 0; i < importSize; i += importInfo.Length) //-V3022 + { + Marshal.Copy(new IntPtr(instance + importPos + i), importInfo, 0, importInfo.Length); + uint token = BitConverter.ToUInt32(importInfo, 0) ^ key; + uint delegateToken = BitConverter.ToUInt32(importInfo, 4) ^ key; + uint callType = BitConverter.ToUInt32(importInfo, 8); + + MethodBase method = null; + FieldInfo field = null; + try + { + if ((callType & 8) != 0) + field = module.ResolveField((int)token); + else + method = module.ResolveMethod((int)token); + } + catch (Exception e) + { + Win32.ShowMessage(e.InnerException.Message, Assembly.GetExecutingAssembly().GetName().Name, MessageBoxButtons.OK, MessageBoxIcon.Error); + Environment.Exit(1); + return; + } + + var invoke = (MethodInfo)module.ResolveMethod((int)delegateToken); + var delegateType = invoke.DeclaringType; + object delegateObject; + if (callType == 0 && method.IsStatic) + delegateObject = Delegate.CreateDelegate(delegateType, (MethodInfo)method); + else + { + ParameterInfo[] parameters = invoke.GetParameters(); + Type[] paramTypes = new Type[parameters.Length]; + for (var j = 0; j < paramTypes.Length; j++) + paramTypes[j] = parameters[j].ParameterType; + + Type declType = (method != null) ? method.DeclaringType : field.DeclaringType; + DynamicMethod dynamicMethod = new DynamicMethod("", invoke.ReturnType, paramTypes, (declType.IsInterface || declType.IsArray) ? delegateType : declType, true); + DynamicILInfo dynamicInfo = dynamicMethod.GetDynamicILInfo(); + dynamicInfo.SetLocalSignature(new byte[] { 0x7, 0x0 }); + + if (method != null) + { + parameters = method.GetParameters(); + int s = 0; + if (paramTypes.Length > parameters.Length) + { + paramTypes[0] = method.DeclaringType; + s = 1; + } + for (var j = 0; j < parameters.Length; j++) + paramTypes[s + j] = parameters[j].ParameterType; + } + else + { + if (paramTypes.Length > 0) + paramTypes[0] = field.DeclaringType; + } + + var code = new byte[7 * paramTypes.Length + 6]; + int codePos = 0; + int dynamicToken; + for (var j = 0; j < paramTypes.Length; j++) + { + code[codePos++] = 0x0e; // Ldarg_s + code[codePos++] = (byte)j; + + Type type = paramTypes[j]; + if ((type.IsClass || type.IsInterface) && !type.IsPointer && !type.IsByRef) + { + code[codePos++] = 0x74; // Castclass + dynamicToken = dynamicInfo.GetTokenFor(type.TypeHandle); + code[codePos++] = (byte)dynamicToken; + code[codePos++] = (byte)(dynamicToken >> 8); + code[codePos++] = (byte)(dynamicToken >> 16); + code[codePos++] = (byte)(dynamicToken >> 24); + } + else + codePos += 5; + } + + switch (callType) + { + case 1: + code[codePos++] = 0x73; // Newobj + break; + case 2: + code[codePos++] = 0x6f; // Callvirt + break; + case 8: + code[codePos++] = 0x7e; // Ldsfld + break; + case 9: + code[codePos++] = 0x7b; // Ldfld + break; + default: + code[codePos++] = 0x28; // Call + break; + } + dynamicToken = (method != null) ? dynamicInfo.GetTokenFor(method.MethodHandle) : dynamicInfo.GetTokenFor(field.FieldHandle); + code[codePos++] = (byte)dynamicToken; + code[codePos++] = (byte)(dynamicToken >> 8); + code[codePos++] = (byte)(dynamicToken >> 16); + code[codePos++] = (byte)(dynamicToken >> 24); + + code[codePos] = 0x2a; // Ret + dynamicInfo.SetCode(code, paramTypes.Length + 1); + + delegateObject = dynamicMethod.CreateDelegate(delegateType); + } + iat[index++] = delegateObject; + } + IAT = iat; + } + + ShowMessage((uint)MessageType.UnregisteredVersion); + + GlobalData.SetLoaderStatus(1); + } + } +}
\ No newline at end of file diff --git a/runtime/VMProtect.Runtime/LzmaDecoder.cs b/runtime/VMProtect.Runtime/LzmaDecoder.cs new file mode 100644 index 0000000..d757b0f --- /dev/null +++ b/runtime/VMProtect.Runtime/LzmaDecoder.cs @@ -0,0 +1,651 @@ +// LzmaDecoder.cs + +using System; +using System.IO; +using SevenZip.Compression.RangeCoder; +#pragma warning disable 414 + +namespace SevenZip.Compression.LZ +{ + public class OutWindow + { + byte[] _buffer; + uint _pos; + uint _windowSize; + uint _streamPos; + Stream _stream; + uint _id = 1; + + public uint TrainSize; + + public void Create(uint windowSize) + { + if (_windowSize != windowSize) + { + _buffer = new byte[windowSize]; + } + _windowSize = windowSize; + _pos = 0; + _streamPos = 0; + } + + public void Init(Stream stream, bool solid) + { + ReleaseStream(); + _stream = stream; + if (!solid) + { + _streamPos = 0; + _pos = 0; + TrainSize = 0; + } + } + + public void ReleaseStream() + { + Flush(); + _stream = null; + } + + public void Flush() + { + uint size = _pos - _streamPos; + if (size == 0) + return; + _stream.Write(_buffer, (int)_streamPos, (int)size); + if (_pos >= _windowSize) + _pos = 0; + _streamPos = _pos; + } + + public void CopyBlock(uint distance, uint len) + { + uint pos = _pos - distance - 1; + if (pos >= _windowSize) + pos += _windowSize; + for (; len > 0; len--) + { + if (pos >= _windowSize) + pos = 0; + _buffer[_pos++] = _buffer[pos++]; + if (_pos >= _windowSize) + Flush(); + } + } + + public void PutByte(byte b) + { + _buffer[_pos++] = b; + if (_pos >= _windowSize) + Flush(); + } + + public byte GetByte(uint distance) + { + uint pos = _pos - distance - 1; + if (pos >= _windowSize) + pos += _windowSize; + return _buffer[pos]; + } + } +} + +namespace SevenZip.Compression.RangeCoder +{ + class Decoder + { + uint _id = 1; + + public const uint KTopValue = (1 << 24); + public uint Range; + public uint Code; + public Stream Stream; + + public void Init(Stream stream) + { + Stream = stream; + + Code = 0; + Range = 0xFFFFFFFF; + for (int i = 0; i < 5; i++) + Code = (Code << 8) | (byte)Stream.ReadByte(); + } + + public void ReleaseStream() + { + Stream = null; + } + + + public uint DecodeDirectBits(int numTotalBits) + { + uint range = Range; + uint code = Code; + uint result = 0; + for (int i = numTotalBits; i > 0; i--) + { + range >>= 1; + uint t = (code - range) >> 31; + code -= range & (t - 1); + result = (result << 1) | (1 - t); + + if (range < KTopValue) + { + code = (code << 8) | (byte)Stream.ReadByte(); + range <<= 8; + } + } + Range = range; + Code = code; + return result; + } + } + + struct BitDecoder + { + private const int KNumBitModelTotalBits = 11; + private const uint KBitModelTotal = (1 << KNumBitModelTotalBits); + const int KNumMoveBits = 5; + + uint _prob; + + public void Init() { _prob = KBitModelTotal >> 1; } + + public uint Decode(Decoder rangeDecoder) + { + uint newBound = (rangeDecoder.Range >> KNumBitModelTotalBits) * _prob; + if (rangeDecoder.Code < newBound) + { + rangeDecoder.Range = newBound; + _prob += (KBitModelTotal - _prob) >> KNumMoveBits; + if (rangeDecoder.Range < Decoder.KTopValue) + { + rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte(); + rangeDecoder.Range <<= 8; + } + return 0; + } + else + { + rangeDecoder.Range -= newBound; + rangeDecoder.Code -= newBound; + _prob -= (_prob) >> KNumMoveBits; + if (rangeDecoder.Range < Decoder.KTopValue) + { + rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte(); + rangeDecoder.Range <<= 8; + } + return 1; + } + } + } + + struct BitTreeDecoder + { + private readonly BitDecoder[] _models; + private readonly int _numBitLevels; + + public BitTreeDecoder(int numBitLevels) + { + _numBitLevels = numBitLevels; + _models = new BitDecoder[1 << numBitLevels]; + } + + public void Init() + { + for (uint i = 1; i < (1 << _numBitLevels); i++) + _models[i].Init(); + } + + public uint Decode(Decoder rangeDecoder) + { + uint m = 1; + for (int bitIndex = _numBitLevels; bitIndex > 0; bitIndex--) + m = (m << 1) + _models[m].Decode(rangeDecoder); + return m - ((uint)1 << _numBitLevels); + } + + public uint ReverseDecode(Decoder rangeDecoder) + { + uint m = 1; + uint symbol = 0; + for (int bitIndex = 0; bitIndex < _numBitLevels; bitIndex++) + { + uint bit = _models[m].Decode(rangeDecoder); + m <<= 1; + m += bit; + symbol |= (bit << bitIndex); + } + return symbol; + } + + public static uint ReverseDecode(BitDecoder[] models, UInt32 startIndex, + Decoder rangeDecoder, int numBitLevels) + { + uint m = 1; + uint symbol = 0; + for (int bitIndex = 0; bitIndex < numBitLevels; bitIndex++) + { + uint bit = models[startIndex + m].Decode(rangeDecoder); + m <<= 1; + m += bit; + symbol |= (bit << bitIndex); + } + return symbol; + } + } +} + +namespace SevenZip.Compression.LZMA +{ + internal abstract class Base + { + public const uint KNumStates = 12; + + public struct State + { + public uint Index; + public void Init() { Index = 0; } + public void UpdateChar() + { + if (Index < 4) Index = 0; + else if (Index < 10) Index -= 3; + else Index -= 6; + } + public void UpdateMatch() { Index = (uint)(Index < 7 ? 7 : 10); } + public void UpdateRep() { Index = (uint)(Index < 7 ? 8 : 11); } + public void UpdateShortRep() { Index = (uint)(Index < 7 ? 9 : 11); } + public bool IsCharState() { return Index < 7; } + } + + public const int KNumPosSlotBits = 6; + + private const int KNumLenToPosStatesBits = 2; // it's for speed optimization + public const uint KNumLenToPosStates = 1 << KNumLenToPosStatesBits; + + public const uint KMatchMinLen = 2; + + public static uint GetLenToPosState(uint len) + { + len -= KMatchMinLen; + if (len < KNumLenToPosStates) + return len; + return KNumLenToPosStates - 1; + } + + public const int KNumAlignBits = 4; + + public const uint KStartPosModelIndex = 4; + public const uint KEndPosModelIndex = 14; + + public const uint KNumFullDistances = 1 << ((int)KEndPosModelIndex / 2); + + public const int KNumPosStatesBitsMax = 4; + public const uint KNumPosStatesMax = (1 << KNumPosStatesBitsMax); + + public const int KNumLowLenBits = 3; + public const int KNumMidLenBits = 3; + public const int KNumHighLenBits = 8; + public const uint KNumLowLenSymbols = 1 << KNumLowLenBits; + public const uint KNumMidLenSymbols = 1 << KNumMidLenBits; + } + public class Decoder + { + uint _id = 1; + + class LenDecoder + { + BitDecoder _mChoice = new BitDecoder(); + BitDecoder _mChoice2 = new BitDecoder(); + readonly BitTreeDecoder[] _mLowCoder = new BitTreeDecoder[Base.KNumPosStatesMax]; + readonly BitTreeDecoder[] _mMidCoder = new BitTreeDecoder[Base.KNumPosStatesMax]; + BitTreeDecoder _mHighCoder = new BitTreeDecoder(Base.KNumHighLenBits); + uint _mNumPosStates; + + public void Create(uint numPosStates) + { + for (uint posState = _mNumPosStates; posState < numPosStates; posState++) + { + _mLowCoder[posState] = new BitTreeDecoder(Base.KNumLowLenBits); + _mMidCoder[posState] = new BitTreeDecoder(Base.KNumMidLenBits); + } + _mNumPosStates = numPosStates; + } + + public void Init() + { + _mChoice.Init(); + for (uint posState = 0; posState < _mNumPosStates; posState++) + { + _mLowCoder[posState].Init(); + _mMidCoder[posState].Init(); + } + _mChoice2.Init(); + _mHighCoder.Init(); + } + + public uint Decode(RangeCoder.Decoder rangeDecoder, uint posState) + { + if (_mChoice.Decode(rangeDecoder) == 0) + return _mLowCoder[posState].Decode(rangeDecoder); + else + { + uint symbol = Base.KNumLowLenSymbols; + if (_mChoice2.Decode(rangeDecoder) == 0) + symbol += _mMidCoder[posState].Decode(rangeDecoder); + else + { + symbol += Base.KNumMidLenSymbols; + symbol += _mHighCoder.Decode(rangeDecoder); + } + return symbol; + } + } + } + + class LiteralDecoder + { + uint _id = 1; + + struct Decoder2 + { + BitDecoder[] _mDecoders; + public void Create() { _mDecoders = new BitDecoder[0x300]; } + public void Init() { for (int i = 0; i < 0x300; i++) _mDecoders[i].Init(); } + + public byte DecodeNormal(RangeCoder.Decoder rangeDecoder) + { + uint symbol = 1; + do + symbol = (symbol << 1) | _mDecoders[symbol].Decode(rangeDecoder); + while (symbol < 0x100); + return (byte)symbol; + } + + public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, byte matchByte) + { + uint symbol = 1; + do + { + uint matchBit = (uint)(matchByte >> 7) & 1; + matchByte <<= 1; + uint bit = _mDecoders[((1 + matchBit) << 8) + symbol].Decode(rangeDecoder); + symbol = (symbol << 1) | bit; + if (matchBit != bit) + { + while (symbol < 0x100) + symbol = (symbol << 1) | _mDecoders[symbol].Decode(rangeDecoder); + break; + } + } + while (symbol < 0x100); + return (byte)symbol; + } + } + + Decoder2[] _mCoders; + int _mNumPrevBits; + int _mNumPosBits; + uint _mPosMask; + + public void Create(int numPosBits, int numPrevBits) + { + if (_mCoders != null && _mNumPrevBits == numPrevBits && + _mNumPosBits == numPosBits) + return; + _mNumPosBits = numPosBits; + _mPosMask = ((uint)1 << numPosBits) - 1; + _mNumPrevBits = numPrevBits; + uint numStates = (uint)1 << (_mNumPrevBits + _mNumPosBits); + _mCoders = new Decoder2[numStates]; + for (uint i = 0; i < numStates; i++) + _mCoders[i].Create(); + } + + public void Init() + { + uint numStates = (uint)1 << (_mNumPrevBits + _mNumPosBits); + for (uint i = 0; i < numStates; i++) + _mCoders[i].Init(); + } + + uint GetState(uint pos, byte prevByte) + { return ((pos & _mPosMask) << _mNumPrevBits) + (uint)(prevByte >> (8 - _mNumPrevBits)); } + + public byte DecodeNormal(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte) + { return _mCoders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); } + + public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte) + { return _mCoders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); } + }; + + readonly LZ.OutWindow _mOutWindow = new LZ.OutWindow(); + readonly RangeCoder.Decoder _mRangeDecoder = new RangeCoder.Decoder(); + + readonly BitDecoder[] _mIsMatchDecoders = new BitDecoder[Base.KNumStates << Base.KNumPosStatesBitsMax]; + readonly BitDecoder[] _mIsRepDecoders = new BitDecoder[Base.KNumStates]; + readonly BitDecoder[] _mIsRepG0Decoders = new BitDecoder[Base.KNumStates]; + readonly BitDecoder[] _mIsRepG1Decoders = new BitDecoder[Base.KNumStates]; + readonly BitDecoder[] _mIsRepG2Decoders = new BitDecoder[Base.KNumStates]; + readonly BitDecoder[] _mIsRep0LongDecoders = new BitDecoder[Base.KNumStates << Base.KNumPosStatesBitsMax]; + + readonly BitTreeDecoder[] _mPosSlotDecoder = new BitTreeDecoder[Base.KNumLenToPosStates]; + readonly BitDecoder[] _mPosDecoders = new BitDecoder[Base.KNumFullDistances - Base.KEndPosModelIndex]; + + BitTreeDecoder _mPosAlignDecoder = new BitTreeDecoder(Base.KNumAlignBits); + + readonly LenDecoder _mLenDecoder = new LenDecoder(); + readonly LenDecoder _mRepLenDecoder = new LenDecoder(); + + readonly LiteralDecoder _mLiteralDecoder = new LiteralDecoder(); + + uint _mDictionarySize; + uint _mDictionarySizeCheck; + + uint _mPosStateMask; + + public Decoder() + { + _mDictionarySize = 0xFFFFFFFF; + for (int i = 0; i < Base.KNumLenToPosStates; i++) + _mPosSlotDecoder[i] = new BitTreeDecoder(Base.KNumPosSlotBits); + } + + void SetDictionarySize(uint dictionarySize) + { + if (_mDictionarySize != dictionarySize) + { + _mDictionarySize = dictionarySize; + _mDictionarySizeCheck = Math.Max(_mDictionarySize, 1); + uint blockSize = Math.Max(_mDictionarySizeCheck, (1 << 12)); + _mOutWindow.Create(blockSize); + } + } + + void SetLiteralProperties(int lp, int lc) + { + if (lp > 8) + throw new ArgumentException("lp > 8"); + if (lc > 8) + throw new ArgumentException("lc > 8"); + _mLiteralDecoder.Create(lp, lc); + } + + void SetPosBitsProperties(int pb) + { + if (pb > Base.KNumPosStatesBitsMax) + throw new ArgumentException("pb > Base.KNumPosStatesBitsMax"); + uint numPosStates = (uint)1 << pb; + _mLenDecoder.Create(numPosStates); + _mRepLenDecoder.Create(numPosStates); + _mPosStateMask = numPosStates - 1; + } + + void Init(Stream inStream, Stream outStream) + { + _mRangeDecoder.Init(inStream); + _mOutWindow.Init(outStream, false); + + uint i; + for (i = 0; i < Base.KNumStates; i++) + { + for (uint j = 0; j <= _mPosStateMask; j++) + { + uint index = (i << Base.KNumPosStatesBitsMax) + j; + _mIsMatchDecoders[index].Init(); + _mIsRep0LongDecoders[index].Init(); + } + _mIsRepDecoders[i].Init(); + _mIsRepG0Decoders[i].Init(); + _mIsRepG1Decoders[i].Init(); + _mIsRepG2Decoders[i].Init(); + } + + _mLiteralDecoder.Init(); + for (i = 0; i < Base.KNumLenToPosStates; i++) + _mPosSlotDecoder[i].Init(); + for (i = 0; i < Base.KNumFullDistances - Base.KEndPosModelIndex; i++) + _mPosDecoders[i].Init(); + + _mLenDecoder.Init(); + _mRepLenDecoder.Init(); + _mPosAlignDecoder.Init(); + } + + public void Code(Stream inStream, Stream outStream, Int64 outSize) + { + Init(inStream, outStream); + + Base.State state = new Base.State(); + state.Init(); + uint rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0; + + UInt64 nowPos64 = 0; + UInt64 outSize64 = (UInt64)outSize; + if (nowPos64 < outSize64) + { + if (_mIsMatchDecoders[state.Index << Base.KNumPosStatesBitsMax].Decode(_mRangeDecoder) != 0) + throw new InvalidDataException("IsMatchDecoders"); + state.UpdateChar(); + byte b = _mLiteralDecoder.DecodeNormal(_mRangeDecoder, 0, 0); + _mOutWindow.PutByte(b); + nowPos64++; + } + while (nowPos64 < outSize64) + { + // UInt64 next = Math.Min(nowPos64 + (1 << 18), outSize64); + // while(nowPos64 < next) + { + uint posState = (uint)nowPos64 & _mPosStateMask; + if (_mIsMatchDecoders[(state.Index << Base.KNumPosStatesBitsMax) + posState].Decode(_mRangeDecoder) == 0) + { + byte b; + byte prevByte = _mOutWindow.GetByte(0); + if (!state.IsCharState()) + b = _mLiteralDecoder.DecodeWithMatchByte(_mRangeDecoder, + (uint)nowPos64, prevByte, _mOutWindow.GetByte(rep0)); + else + b = _mLiteralDecoder.DecodeNormal(_mRangeDecoder, (uint)nowPos64, prevByte); + _mOutWindow.PutByte(b); + state.UpdateChar(); + nowPos64++; + } + else + { + uint len; + if (_mIsRepDecoders[state.Index].Decode(_mRangeDecoder) == 1) + { + if (_mIsRepG0Decoders[state.Index].Decode(_mRangeDecoder) == 0) + { + if (_mIsRep0LongDecoders[(state.Index << Base.KNumPosStatesBitsMax) + posState].Decode(_mRangeDecoder) == 0) + { + state.UpdateShortRep(); + _mOutWindow.PutByte(_mOutWindow.GetByte(rep0)); + nowPos64++; + continue; + } + } + else + { + UInt32 distance; + if (_mIsRepG1Decoders[state.Index].Decode(_mRangeDecoder) == 0) + { + distance = rep1; + } + else + { + if (_mIsRepG2Decoders[state.Index].Decode(_mRangeDecoder) == 0) + distance = rep2; + else + { + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + len = _mRepLenDecoder.Decode(_mRangeDecoder, posState) + Base.KMatchMinLen; + state.UpdateRep(); + } + else + { + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + len = Base.KMatchMinLen + _mLenDecoder.Decode(_mRangeDecoder, posState); + state.UpdateMatch(); + uint posSlot = _mPosSlotDecoder[Base.GetLenToPosState(len)].Decode(_mRangeDecoder); + if (posSlot >= Base.KStartPosModelIndex) + { + int numDirectBits = (int)((posSlot >> 1) - 1); + rep0 = ((2 | (posSlot & 1)) << numDirectBits); + if (posSlot < Base.KEndPosModelIndex) + rep0 += BitTreeDecoder.ReverseDecode(_mPosDecoders, + rep0 - posSlot - 1, _mRangeDecoder, numDirectBits); + else + { + rep0 += (_mRangeDecoder.DecodeDirectBits( + numDirectBits - Base.KNumAlignBits) << Base.KNumAlignBits); + rep0 += _mPosAlignDecoder.ReverseDecode(_mRangeDecoder); + } + } + else + rep0 = posSlot; + } + if (rep0 >= _mOutWindow.TrainSize + nowPos64 || rep0 >= _mDictionarySizeCheck) + { + if (rep0 == 0xFFFFFFFF) + break; + throw new InvalidDataException("rep0"); + } + _mOutWindow.CopyBlock(rep0, len); + nowPos64 += len; + } + } + } + _mOutWindow.Flush(); + _mOutWindow.ReleaseStream(); + _mRangeDecoder.ReleaseStream(); + } + + public void SetDecoderProperties(byte[] properties) + { + if (properties.Length < 5) + throw new ArgumentException("properties.Length < 5"); + int lc = properties[0] % 9; + int remainder = properties[0] / 9; + int lp = remainder % 5; + int pb = remainder / 5; + if (pb > Base.KNumPosStatesBitsMax) + throw new ArgumentException("pb > Base.kNumPosStatesBitsMax"); + UInt32 dictionarySize = 0; + for (int i = 0; i < 4; i++) + dictionarySize += ((UInt32)(properties[1 + i])) << (i * 8); + SetDictionarySize(dictionarySize); + SetLiteralProperties(lp, lc); + SetPosBitsProperties(pb); + } + } +} diff --git a/runtime/VMProtect.Runtime/Numerics/BigInteger.cs b/runtime/VMProtect.Runtime/Numerics/BigInteger.cs new file mode 100644 index 0000000..b124460 --- /dev/null +++ b/runtime/VMProtect.Runtime/Numerics/BigInteger.cs @@ -0,0 +1,2012 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +/*============================================================================= +** +** Struct: BigInteger +** +** Purpose: Represents an arbitrary precision integer. +** +=============================================================================*/ + +using System; + +using Contracts = System.Diagnostics.Debug; +using Contract = System.Diagnostics.Debug; +//using System.Globalization; +// ReSharper disable InconsistentNaming + +// ReSharper disable once CheckNamespace +namespace Numerics +{ +#if !SILVERLIGHT + [Serializable] +#endif // !SILVERLIGHT + internal struct BigInteger /*: IFormattable, IComparable, IComparable<BigInteger>, IEquatable<BigInteger>*/ + { + // ---- SECTION: members supporting exposed properties -------------* + #region members supporting exposed properties + private const uint kuMaskHighBit = unchecked((uint)int.MinValue); + private const int kcbitUint = 32; + //private const int kcbitUlong = 64; + //private const int DecimalScaleFactorMask = 0x00FF0000; + //private const int DecimalSignMask = unchecked((int)0x80000000); + + // For values int.MinValue < n <= int.MaxValue, the value is stored in sign + // and _bits is null. For all other values, sign is +1 or -1 and the bits are in _bits + private readonly int _sign; + private readonly uint[] _bits; + + // We have to make a choice of how to represent int.MinValue. This is the one + // value that fits in an int, but whose negation does not fit in an int. + // We choose to use a large representation, so we're symmetric with respect to negation. + private static readonly BigInteger s_bnMinInt = new BigInteger(-1, new[] { kuMaskHighBit }); + private static readonly BigInteger s_bnOneInt = new BigInteger(1); + private static readonly BigInteger s_bnZeroInt = new BigInteger(0); + private static readonly BigInteger s_bnMinusOneInt = new BigInteger(-1); + +#if CONTRACTS_FULL + [ContractInvariantMethod] + private void ObjectInvariant() + { + Contract.Invariant((_bits == null) ? _sign > Int32.MinValue : + ((_sign == 1 || _sign == -1) && Length(_bits) > 0)); + Contract.Invariant(_bits == null || Length(_bits) > 1 || _bits[0] >= kuMaskHighBit + , "One element array stores integers whose absolute value is between 0x80000000 and 0xFFFFFFFF"); + } +#endif + + [System.Diagnostics.Conditional("DEBUG")] + private void AssertValid() + { + if (_bits != null) + { + Contracts.Assert(_sign == 1 || _sign == -1 /*, "_sign must be +1 or -1 when _bits is non-null"*/); + Contracts.Assert(Length(_bits) > 0 /*, "_bits must contain at least 1 element or be null"*/); + if (Length(_bits) == 1) + Contracts.Assert(_bits[0] >= kuMaskHighBit /*, "Wasted space _bits[0] could have been packed into _sign"*/); + } + else + Contracts.Assert(_sign > int.MinValue /*, "Int32.MinValue should not be stored in the _sign field"*/); + } + #endregion members supporting exposed properties + + // ---- SECTION: internal properties --------------* + #region internal properties + + /*internal static BigInteger Zero + { + get { return s_bnZeroInt; } + }*/ + + private static BigInteger One + { + get { return s_bnOneInt; } + } + +/* + internal static BigInteger MinusOne + { + get { return s_bnMinusOneInt; } + } + + internal bool IsPowerOfTwo + { + get + { + AssertValid(); + + if (_bits == null) + return (_sign & (_sign - 1)) == 0 && _sign != 0; + + if (_sign != 1) + return false; + int iu = Length(_bits) - 1; + if ((_bits[iu] & (_bits[iu] - 1)) != 0) + return false; + while (--iu >= 0) + { + if (_bits[iu] != 0) + return false; + } + return true; + } + } +*/ + +/* + internal bool IsZero { get { AssertValid(); return _sign == 0; } } +*/ + +/* + internal bool IsOne { get { AssertValid(); return _sign == 1 && _bits == null; } } +*/ + + private bool IsEven { get { AssertValid(); return _bits == null ? (_sign & 1) == 0 : (_bits[0] & 1) == 0; } } + + private int Sign + { + get { AssertValid(); return (_sign >> (kcbitUint - 1)) - (-_sign >> (kcbitUint - 1)); } + } + + #endregion internal properties + + + // ---- SECTION: internal instance methods --------------* + #region internal instance methods + + public override bool Equals(object obj) + { + AssertValid(); + + if (!(obj is BigInteger)) + return false; + return Equals((BigInteger)obj); + } + + public override int GetHashCode() + { + AssertValid(); + + // ReSharper disable NonReadonlyMemberInGetHashCode + if (_bits == null) + return _sign; + var hash = _sign; + for (var iv = Length(_bits); --iv >= 0; ) + hash = NumericsHelpers.CombineHash(hash, (int)_bits[iv]); + return hash; + } + + /*public bool Equals(Int64 other) + { + AssertValid(); + + if (_bits == null) + return _sign == other; + + int cu; + if ((_sign ^ other) < 0 || (cu = Length(_bits)) > 2) + return false; + + var uu = other < 0 ? (ulong)-other : (ulong)other; + if (cu == 1) + return _bits[0] == uu; + + return NumericsHelpers.MakeUlong(_bits[1], _bits[0]) == uu; + } + + public bool Equals(UInt64 other) + { + AssertValid(); + + if (_sign < 0) + return false; + if (_bits == null) + return (ulong)_sign == other; + + var cu = Length(_bits); + if (cu > 2) + return false; + if (cu == 1) + return _bits[0] == other; + return NumericsHelpers.MakeUlong(_bits[1], _bits[0]) == other; + }*/ + + /*public bool Equals(BigInteger other) + { + AssertValid(); + other.AssertValid(); + + if (_sign != other._sign) + return false; + if (_bits == other._bits) + // _sign == other._sign && _bits == null && other._bits == null + return true; + + if (_bits == null || other._bits == null) + return false; + var cu = Length(_bits); + if (cu != Length(other._bits)) + return false; + var cuDiff = GetDiffLength(_bits, other._bits, cu); + return cuDiff == 0; + }*/ + + /*internal int CompareTo(Int64 other) + { + AssertValid(); + + if (_bits == null) + return ((long)_sign).CompareTo(other); + int cu; + if ((_sign ^ other) < 0 || (cu = Length(_bits)) > 2) + return _sign; + var uu = other < 0 ? (ulong)-other : (ulong)other; + var uuTmp = cu == 2 ? NumericsHelpers.MakeUlong(_bits[1], _bits[0]) : _bits[0]; + return _sign * uuTmp.CompareTo(uu); + } + + internal int CompareTo(UInt64 other) + { + AssertValid(); + + if (_sign < 0) + return -1; + if (_bits == null) + return ((ulong)_sign).CompareTo(other); + var cu = Length(_bits); + if (cu > 2) + return +1; + var uuTmp = cu == 2 ? NumericsHelpers.MakeUlong(_bits[1], _bits[0]) : _bits[0]; + return uuTmp.CompareTo(other); + }*/ + + private int CompareTo(BigInteger other) + { + AssertValid(); + other.AssertValid(); + + if ((_sign ^ other._sign) < 0) + { + // Different signs, so the comparison is easy. + return _sign < 0 ? -1 : +1; + } + + // Same signs + if (_bits == null) + { + if (other._bits == null) + return _sign < other._sign ? -1 : _sign > other._sign ? +1 : 0; + return -other._sign; + } + int cuThis, cuOther; + if (other._bits == null || (cuThis = Length(_bits)) > (cuOther = Length(other._bits))) + return _sign; + if (cuThis < cuOther) + return -_sign; + + var cuDiff = GetDiffLength(_bits, other._bits, cuThis); + if (cuDiff == 0) + return 0; + return _bits[cuDiff - 1] < other._bits[cuDiff - 1] ? -_sign : _sign; + } + +/* + public int CompareTo(Object obj) + { + if (obj == null) + return 1; + if (!(obj is BigInteger)) + throw new ArgumentException("Argument must be BigInteger", "obj"); + return CompareTo((BigInteger)obj); + } +*/ + + + // Return the value of this BigInteger as a little-endian twos-complement + // byte array, using the fewest number of bytes possible. If the value is zero, + // return an array of one byte whose element is 0x00. + internal byte[] ToByteArray() + { + if (_bits == null && _sign == 0) + return new byte[] { 0 }; + + // We could probably make this more efficient by eliminating one of the passes. + // The current code does one pass for uint array -> byte array conversion, + // and then another pass to remove unneeded bytes at the top of the array. + uint[] dwords; + byte highByte; + + if (_bits == null) + { + dwords = new[] { (uint)_sign }; + highByte = (byte)(_sign < 0 ? 0xff : 0x00); + } + else if (_sign == -1) + { + dwords = (uint[])_bits.Clone(); + NumericsHelpers.DangerousMakeTwosComplement(dwords); // mutates dwords + highByte = 0xff; + } + else + { + dwords = _bits; + highByte = 0x00; + } + + var bytes = new byte[checked(4 * dwords.Length)]; + var curByte = 0; + foreach (var t in dwords) + { + var dword = t; + for (var j = 0; j < 4; j++) + { + bytes[curByte++] = (byte)(dword & 0xff); + dword >>= 8; + } + } + + // ensure high bit is 0 if positive, 1 if negative + if ((bytes[bytes.Length - 1] & 0x80) == (highByte & 0x80)) + return bytes; + + var trimmedBytes = new byte[bytes.Length + 1]; + Array.Copy(bytes, trimmedBytes, bytes.Length); + trimmedBytes[trimmedBytes.Length - 1] = highByte; + return trimmedBytes; + } + + // Return the value of this BigInteger as a little-endian twos-complement + // uint array, using the fewest number of uints possible. If the value is zero, + // return an array of one uint whose element is 0. +/* + private UInt32[] ToUInt32Array() + { + if (_bits == null && _sign == 0) + return new uint[] { 0 }; + + uint[] dwords; + uint highDWord; + + if (_bits == null) + { + dwords = new[] { (uint)_sign }; + highDWord = _sign < 0 ? UInt32.MaxValue : 0; + } + else if (_sign == -1) + { + dwords = (uint[])_bits.Clone(); + NumericsHelpers.DangerousMakeTwosComplement(dwords); // mutates dwords + highDWord = UInt32.MaxValue; + } + else + { + dwords = _bits; + highDWord = 0; + } + + // find highest significant byte + int msb; + for (msb = dwords.Length - 1; msb > 0; msb--) + { + if (dwords[msb] != highDWord) break; + } + // ensure high bit is 0 if positive, 1 if negative + var needExtraByte = (dwords[msb] & 0x80000000) != (highDWord & 0x80000000); + + var trimmed = new uint[msb + 1 + (needExtraByte ? 1 : 0)]; + Array.Copy(dwords, trimmed, msb + 1); + + if (needExtraByte) trimmed[trimmed.Length - 1] = highDWord; + return trimmed; + } +*/ + + /*public override String ToString() + { + return BigNumber.FormatBigInteger(this, null, NumberFormatInfo.CurrentInfo); + } + + internal String ToString(IFormatProvider provider) + { + return BigNumber.FormatBigInteger(this, null, NumberFormatInfo.GetInstance(provider)); + } + + internal String ToString(String format) + { + return BigNumber.FormatBigInteger(this, format, NumberFormatInfo.CurrentInfo); + } + + public String ToString(String format, IFormatProvider provider) + { + return BigNumber.FormatBigInteger(this, format, NumberFormatInfo.GetInstance(provider)); + }*/ + #endregion internal instance methods + + // -------- SECTION: constructors -----------------* + #region constructors + + private BigInteger(int value) + { + if (value == Int32.MinValue) + this = s_bnMinInt; + else + { + _sign = value; + _bits = null; + } + AssertValid(); + } + +/* + internal BigInteger(uint value) + { + if (value <= Int32.MaxValue) + { + _sign = (int)value; + _bits = null; + } + else + { + _sign = +1; + _bits = new uint[1]; + _bits[0] = value; + } + AssertValid(); + } +*/ + +/* + internal BigInteger(Int64 value) + { + if (Int32.MinValue <= value && value <= Int32.MaxValue) + { + if (value == Int32.MinValue) + this = s_bnMinInt; + else + { + _sign = (int)value; + _bits = null; + } + AssertValid(); + return; + } + + ulong x; + if (value < 0) + { + x = (ulong)-value; + _sign = -1; + } + else + { + Contract.Assert(value != 0); + x = (ulong)value; + _sign = +1; + } + + _bits = new uint[2]; + _bits[0] = (uint)x; + _bits[1] = (uint)(x >> kcbitUint); + AssertValid(); + } +*/ + +/* + internal BigInteger(UInt64 value) + { + if (value <= Int32.MaxValue) + { + _sign = (int)value; + _bits = null; + } + else + { + _sign = +1; + _bits = new uint[2]; + _bits[0] = (uint)value; + _bits[1] = (uint)(value >> kcbitUint); + } + AssertValid(); + } +*/ + + /*internal BigInteger(Single value) + { + if (Single.IsInfinity(value)) + throw new OverflowException("Overflow BigIntInfinity"); + if (Single.IsNaN(value)) + throw new OverflowException("Overflow not a number"); + ////Contract.EndContractBlock(); + + _sign = 0; + _bits = null; + // ReSharper disable once ExpressionIsAlwaysNull + SetBitsFromDouble(value); + AssertValid(); + } + + internal BigInteger(Double value) + { + if (Double.IsInfinity(value)) + throw new OverflowException("Overflow BigIntInfinity"); + if (Double.IsNaN(value)) + throw new OverflowException("Overflow not a number"); + ////Contract.EndContractBlock(); + + _sign = 0; + _bits = null; + // ReSharper disable once ExpressionIsAlwaysNull + SetBitsFromDouble(value); + AssertValid(); + }*/ + + /*internal BigInteger(Decimal value) + { + // First truncate to get scale to 0 and extract bits + var bits = Decimal.GetBits(Decimal.Truncate(value)); + + Contract.Assert(bits.Length == 4 && (bits[3] & DecimalScaleFactorMask) == 0); + + var size = 3; + while (size > 0 && bits[size - 1] == 0) + size--; + if (size == 0) + { + this = s_bnZeroInt; + } + else if (size == 1 && bits[0] > 0) + { + // bits[0] is the absolute value of this decimal + // if bits[0] < 0 then it is too large to be packed into _sign + _sign = bits[0]; + _sign *= (bits[3] & DecimalSignMask) != 0 ? -1 : +1; + _bits = null; + } + else + { + _bits = new UInt32[size]; + _bits[0] = (UInt32)bits[0]; + if (size > 1) + _bits[1] = (UInt32)bits[1]; + if (size > 2) + _bits[2] = (UInt32)bits[2]; + _sign = (bits[3] & DecimalSignMask) != 0 ? -1 : +1; + } + AssertValid(); + }*/ + + // + // Create a BigInteger from a little-endian twos-complement byte array + // + internal BigInteger(Byte[] value) + { + if (value == null) + throw new ArgumentNullException("value"); + //Contract.EndContractBlock(); + + var byteCount = value.Length; + var isNegative = byteCount > 0 && ((value[byteCount - 1] & 0x80) == 0x80); + + // Try to conserve space as much as possible by checking for wasted leading byte[] entries + while (byteCount > 0 && value[byteCount - 1] == 0) byteCount--; + + if (byteCount == 0) + { + // BigInteger.Zero + _sign = 0; + _bits = null; + // ReSharper disable once ExpressionIsAlwaysNull + AssertValid(); + return; + } + + + if (byteCount <= 4) + { + if (isNegative) + _sign = unchecked((int)0xffffffff); + else + _sign = 0; + for (var i = byteCount - 1; i >= 0; i--) + { + _sign <<= 8; + _sign |= value[i]; + } + _bits = null; + + if (_sign < 0 && !isNegative) + { + // int32 overflow + // example: Int64 value 2362232011 (0xCB, 0xCC, 0xCC, 0x8C, 0x0) + // can be naively packed into 4 bytes (due to the leading 0x0) + // it overflows into the int32 sign bit + _bits = new uint[1]; + _bits[0] = (uint)_sign; + _sign = +1; + } + if (_sign == Int32.MinValue) + this = s_bnMinInt; + } + else + { + var unalignedBytes = byteCount % 4; + var dwordCount = byteCount / 4 + (unalignedBytes == 0 ? 0 : 1); + var isZero = true; + var val = new uint[dwordCount]; + + // Copy all dwords, except but don't do the last one if it's not a full four bytes + int curDword; + var curByte = 3; + for (curDword = 0; curDword < dwordCount - (unalignedBytes == 0 ? 0 : 1); curDword++) + { + var byteInDword = 0; + while (byteInDword < 4) + { + if (value[curByte] != 0x00) isZero = false; + val[curDword] <<= 8; + val[curDword] |= value[curByte]; + curByte--; + byteInDword++; + } + curByte += 8; + } + + // Copy the last dword specially if it's not aligned + if (unalignedBytes != 0) + { + if (isNegative) val[dwordCount - 1] = 0xffffffff; + for (curByte = byteCount - 1; curByte >= byteCount - unalignedBytes; curByte--) + { + if (value[curByte] != 0x00) isZero = false; + val[curDword] <<= 8; + val[curDword] |= value[curByte]; + } + } + + if (isZero) + { + this = s_bnZeroInt; + } + else if (isNegative) + { + NumericsHelpers.DangerousMakeTwosComplement(val); // mutates val + + // pack _bits to remove any wasted space after the twos complement + var len = val.Length; + while (len > 0 && val[len - 1] == 0) + len--; + if (len == 1 && (int)val[0] > 0) + { + if (val[0] == 1 /* abs(-1) */) + { + this = s_bnMinusOneInt; + } + else if (val[0] == kuMaskHighBit /* abs(Int32.MinValue) */) //TODO: V3022 https://www.viva64.com/en/w/V3022 Expression 'val[0] == kuMaskHighBit' is always false. + { + this = s_bnMinInt; + } + else + { + _sign = -1 * (int)val[0]; + _bits = null; + } + } + else if (len != val.Length) + { + _sign = -1; + _bits = new uint[len]; + Array.Copy(val, _bits, len); + } + else + { + _sign = -1; + _bits = val; + } + } + else + { + _sign = +1; + _bits = val; + } + } + AssertValid(); + } + + internal BigInteger(int n, uint[] rgu) + { + _sign = n; + _bits = rgu; + AssertValid(); + } + + // + // BigInteger(uint[] value, bool negative) + // + // Constructor used during bit manipulation and arithmetic + // + // The uint[] value is expected to be the absolute value of the number + // with the bool negative indicating the Sign of the value. + // + // When possible the uint[] will be packed into _sign to conserve space + // +/* + internal BigInteger(uint[] value, bool negative) + { + if (value == null) + throw new ArgumentNullException("value"); + //Contract.EndContractBlock(); + + int len; + + // Try to conserve space as much as possible by checking for wasted leading uint[] entries + // sometimes the uint[] has leading zeros from bit manipulation operations & and ^ + for (len = value.Length; len > 0 && value[len - 1] == 0; len--) + { + } + + if (len == 0) + this = s_bnZeroInt; + // values like (Int32.MaxValue+1) are stored as "0x80000000" and as such cannot be packed into _sign + else if (len == 1 && value[0] < kuMaskHighBit) + { + _sign = negative ? -(int)value[0] : (int)value[0]; + _bits = null; + // Although Int32.MinValue fits in _sign, we represent this case differently for negate + if (_sign == Int32.MinValue) + this = s_bnMinInt; + } + else + { + _sign = negative ? -1 : +1; + _bits = new uint[len]; + Array.Copy(value, _bits, len); + } + AssertValid(); + } +*/ + + + // + // Create a BigInteger from a little-endian twos-complement UInt32 array + // When possible, value is assigned directly to this._bits without an array copy + // so use this ctor with care + // +// private BigInteger(uint[] value) +// { +// if (value == null) +// throw new ArgumentNullException("value"); +// +// var dwordCount = value.Length; +// var isNegative = dwordCount > 0 && ((value[dwordCount - 1] & 0x80000000) == 0x80000000); +// +// // Try to conserve space as much as possible by checking for wasted leading uint[] entries +// while (dwordCount > 0 && value[dwordCount - 1] == 0) dwordCount--; +// +// if (dwordCount == 0) +// { +// // BigInteger.Zero +// this = s_bnZeroInt; +// AssertValid(); +// return; +// } +// if (dwordCount == 1) +// { +// if ((int)value[0] < 0 && !isNegative) +// { +// _bits = new uint[1]; +// _bits[0] = value[0]; +// _sign = +1; +// } +// // handle the special cases where the BigInteger likely fits into _sign +// else if (Int32.MinValue == (int)value[0]) +// { +// this = s_bnMinInt; +// } +// else +// { +// _sign = (int)value[0]; +// _bits = null; +// } +// AssertValid(); +// return; +// } +// +// if (!isNegative) +// { +// // handle the simple postive value cases where the input is already in sign magnitude +// if (dwordCount != value.Length) +// { +// _sign = +1; +// _bits = new uint[dwordCount]; +// Array.Copy(value, _bits, dwordCount); +// } +// // no trimming is possible. Assign value directly to _bits. +// else +// { +// _sign = +1; +// _bits = value; +// } +// AssertValid(); +// return; +// } +// +// +// // finally handle the more complex cases where we must transform the input into sign magnitude +// NumericsHelpers.DangerousMakeTwosComplement(value); // mutates val +// +// // pack _bits to remove any wasted space after the twos complement +// var len = value.Length; +// while (len > 0 && value[len - 1] == 0) len--; +// +// // the number is represented by a single dword +// if (len == 1 && (int)value[0] > 0) +// { +// if (value[0] == 1 /* abs(-1) */) +// { +// this = s_bnMinusOneInt; +// } +// else if (value[0] == kuMaskHighBit /* abs(Int32.MinValue) */) +// { +// this = s_bnMinInt; +// } +// else +// { +// _sign = -1 * (int)value[0]; +// _bits = null; +// } +// } +// // the number is represented by multiple dwords +// // trim off any wasted uint values when possible +// else if (len != value.Length) +// { +// _sign = -1; +// _bits = new uint[len]; +// Array.Copy(value, _bits, len); +// } +// // no trimming is possible. Assign value directly to _bits. +// else +// { +// _sign = -1; +// _bits = value; +// } +// AssertValid(); +// } + + + #endregion constructors + + + // -------- SECTION: internal static methods -----------------* + #region internal static methods +#if !SILVERLIGHT || FEATURE_NETCORE +/* + internal static BigInteger Parse(String value) + { + return BigNumber.ParseBigInteger(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); + } +*/ + +/* + internal static BigInteger Parse(String value, NumberStyles style) + { + return BigNumber.ParseBigInteger(value, style, NumberFormatInfo.CurrentInfo); + } +*/ + +/* + internal static BigInteger Parse(String value, IFormatProvider provider) + { + return BigNumber.ParseBigInteger(value, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); + } +*/ + +/* + internal static BigInteger Parse(String value, NumberStyles style, IFormatProvider provider) + { + return BigNumber.ParseBigInteger(value, style, NumberFormatInfo.GetInstance(provider)); + } +*/ + +/* + internal static Boolean TryParse(String value, out BigInteger result) + { + return BigNumber.TryParseBigInteger(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); + } +*/ + +/* + internal static Boolean TryParse(String value, NumberStyles style, IFormatProvider provider, out BigInteger result) + { + return BigNumber.TryParseBigInteger(value, style, NumberFormatInfo.GetInstance(provider), out result); + } +*/ +#endif //!SILVERLIGHT || FEATURE_NETCORE + +/* + internal static Int32 Compare(BigInteger left, BigInteger right) + { + return left.CompareTo(right); + } +*/ + +/* + internal static BigInteger Abs(BigInteger value) + { + return value >= Zero ? value : -value; + } +*/ + +/* + internal static BigInteger Add(BigInteger left, BigInteger right) + { + return left + right; + } +*/ + +/* + internal static BigInteger Subtract(BigInteger left, BigInteger right) + { + return left - right; + } +*/ + +/* + internal static BigInteger Multiply(BigInteger left, BigInteger right) + { + return left * right; + } +*/ + +/* + internal static BigInteger Divide(BigInteger dividend, BigInteger divisor) + { + return dividend / divisor; + } +*/ + +/* + internal static BigInteger Remainder(BigInteger dividend, BigInteger divisor) + { + return dividend % divisor; + } +*/ + +/* + internal static BigInteger DivRem(BigInteger dividend, BigInteger divisor, out BigInteger remainder) + { + dividend.AssertValid(); + divisor.AssertValid(); + + var signNum = +1; + var signDen = +1; + var regNum = new BigIntegerBuilder(dividend, ref signNum); + var regDen = new BigIntegerBuilder(divisor, ref signDen); + var regQuo = new BigIntegerBuilder(); + + // regNum and regQuo are overwritten with the remainder and quotient, respectively + regNum.ModDiv(ref regDen, ref regQuo); + remainder = regNum.GetInteger(signNum); + return regQuo.GetInteger(signNum * signDen); + } +*/ + + +/* + internal static BigInteger Negate(BigInteger value) + { + return -value; + } +*/ + + // Returns the natural (base e) logarithm of a specified number. +/* + internal static Double Log(BigInteger value, Double baseValue = Math.E) + { + // ReSharper disable CompareOfFloatsByEqualityOperator + if (value._sign < 0 || baseValue == 1.0D) + return Double.NaN; + if (baseValue == Double.PositiveInfinity) + return value.IsOne ? 0.0D : Double.NaN; + if (baseValue == 0.0D && !value.IsOne) + return Double.NaN; + if (value._bits == null) + return Math.Log(value._sign, baseValue); + // ReSharper restore CompareOfFloatsByEqualityOperator + + Double c = 0, d = 0.5D; + const Double log2 = 0.69314718055994529D; + + var uintLength = Length(value._bits); + var topbits = BitLengthOfUInt(value._bits[uintLength - 1]); + var bitlen = (uintLength - 1) * kcbitUint + topbits; + var indbit = (uint)(1 << (topbits - 1)); + + for (var index = uintLength - 1; index >= 0; --index) + { + while (indbit != 0) + { + if ((value._bits[index] & indbit) != 0) + c += d; + d *= 0.5; + indbit >>= 1; + } + indbit = 0x80000000; + } + return (Math.Log(c) + log2 * bitlen) / Math.Log(baseValue); + } +*/ + + +/* + internal static Double Log10(BigInteger value) + { + return Log(value, 10); + } +*/ + +/* + internal static BigInteger GreatestCommonDivisor(BigInteger left, BigInteger right) + { + left.AssertValid(); + right.AssertValid(); + + // gcd(0, 0) = 0 + // gcd(a, 0) = |a|, for a != 0, since any number is a divisor of 0, and the greatest divisor of a is |a| + if (left._sign == 0) return Abs(right); + if (right._sign == 0) return Abs(left); + + var reg1 = new BigIntegerBuilder(left); + var reg2 = new BigIntegerBuilder(right); + BigIntegerBuilder.GCD(ref reg1, ref reg2); + + return reg1.GetInteger(+1); + } +*/ + +/* + internal static BigInteger Max(BigInteger left, BigInteger right) + { + if (left.CompareTo(right) < 0) + return right; + return left; + } +*/ + +/* + internal static BigInteger Min(BigInteger left, BigInteger right) + { + if (left.CompareTo(right) <= 0) + return left; + return right; + } +*/ + + + private static void ModPowUpdateResult(ref BigIntegerBuilder regRes, ref BigIntegerBuilder regVal, ref BigIntegerBuilder regMod, ref BigIntegerBuilder regTmp) + { + NumericsHelpers.Swap(ref regRes, ref regTmp); + regRes.Mul(ref regTmp, ref regVal); // result = result * value; + regRes.Mod(ref regMod); // result = result % modulus; + } + + private static void ModPowSquareModValue(ref BigIntegerBuilder regVal, ref BigIntegerBuilder regMod, ref BigIntegerBuilder regTmp) + { + NumericsHelpers.Swap(ref regVal, ref regTmp); + regVal.Mul(ref regTmp, ref regTmp); // value = value * value; + regVal.Mod(ref regMod); // value = value % modulus; + } + + private static void ModPowInner(uint exp, ref BigIntegerBuilder regRes, ref BigIntegerBuilder regVal, ref BigIntegerBuilder regMod, ref BigIntegerBuilder regTmp) + { + while (exp != 0) // !(Exponent.IsZero) + { + if ((exp & 1) == 1) // !(Exponent.IsEven) + ModPowUpdateResult(ref regRes, ref regVal, ref regMod, ref regTmp); + if (exp == 1) // Exponent.IsOne - we can exit early + break; + ModPowSquareModValue(ref regVal, ref regMod, ref regTmp); + exp >>= 1; + } + } + + private static void ModPowInner32(uint exp, ref BigIntegerBuilder regRes, ref BigIntegerBuilder regVal, ref BigIntegerBuilder regMod, ref BigIntegerBuilder regTmp) + { + for (var i = 0; i < 32; i++) + { + if ((exp & 1) == 1) // !(Exponent.IsEven) + ModPowUpdateResult(ref regRes, ref regVal, ref regMod, ref regTmp); + ModPowSquareModValue(ref regVal, ref regMod, ref regTmp); + exp >>= 1; + } + } + + internal static BigInteger ModPow(BigInteger value, BigInteger exponent, BigInteger modulus) + { + if (exponent.Sign < 0) + throw new ArgumentOutOfRangeException("exponent", "ArgumentOutOfRange must be non negative"); + //Contract.EndContractBlock(); + + value.AssertValid(); + exponent.AssertValid(); + modulus.AssertValid(); + + var signRes = +1; + var signVal = +1; + var signMod = +1; + var expIsEven = exponent.IsEven; + var regRes = new BigIntegerBuilder(One, ref signRes); + var regVal = new BigIntegerBuilder(value, ref signVal); + var regMod = new BigIntegerBuilder(modulus, ref signMod); + var regTmp = new BigIntegerBuilder(regVal.Size); + + regRes.Mod(ref regMod); // Handle special case of exponent=0, modulus=1 + + if (exponent._bits == null) + { // exponent fits into an Int32 + ModPowInner((uint)exponent._sign, ref regRes, ref regVal, ref regMod, ref regTmp); + } + else + { // very large exponent + var len = Length(exponent._bits); + for (var i = 0; i < len - 1; i++) + { + var exp = exponent._bits[i]; + ModPowInner32(exp, ref regRes, ref regVal, ref regMod, ref regTmp); + } + ModPowInner(exponent._bits[len - 1], ref regRes, ref regVal, ref regMod, ref regTmp); + } + + return regRes.GetInteger(value._sign > 0 ? +1 : expIsEven ? +1 : -1); + } + +/* + internal static BigInteger Pow(BigInteger value, Int32 exponent) + { + if (exponent < 0) + throw new ArgumentOutOfRangeException("exponent", "ArgumentOutOfRange must be non negative"); + //Contract.EndContractBlock(); + + value.AssertValid(); + + if (exponent == 0) + return One; + if (exponent == 1) + return value; + if (value._bits == null) + { + if (value._sign == 1) + return value; + if (value._sign == -1) + return (exponent & 1) != 0 ? value : 1; + if (value._sign == 0) + return value; + } + + var sign = +1; + var regSquare = new BigIntegerBuilder(value, ref sign); + + // Get an estimate of the size needed for regSquare and regRes, so we can minimize allocations. + var cuSquareMin = regSquare.Size; + var cuSquareMax = cuSquareMin; + var uSquareMin = regSquare.High; + var uSquareMax = uSquareMin + 1; + if (uSquareMax == 0) + { + cuSquareMax++; + uSquareMax = 1; + } + var cuResMin = 1; + var cuResMax = 1; + uint uResMin = 1; + uint uResMax = 1; + + for (var expTmp = exponent; ; ) + { + if ((expTmp & 1) != 0) + { + MulUpper(ref uResMax, ref cuResMax, uSquareMax, cuSquareMax); + MulLower(ref uResMin, ref cuResMin, uSquareMin, cuSquareMin); + } + + if ((expTmp >>= 1) == 0) + break; + + MulUpper(ref uSquareMax, ref cuSquareMax, uSquareMax, cuSquareMax); + MulLower(ref uSquareMin, ref cuSquareMin, uSquareMin, cuSquareMin); + } + + if (cuResMax > 1) + regSquare.EnsureWritable(cuResMax, 0); + var regTmp = new BigIntegerBuilder(cuResMax); + var regRes = new BigIntegerBuilder(cuResMax); + regRes.Set(1); + + if ((exponent & 1) == 0) + sign = +1; + + for (var expTmp = exponent; ; ) + { + if ((expTmp & 1) != 0) + { + NumericsHelpers.Swap(ref regRes, ref regTmp); + regRes.Mul(ref regSquare, ref regTmp); + } + if ((expTmp >>= 1) == 0) + break; + NumericsHelpers.Swap(ref regSquare, ref regTmp); + regSquare.Mul(ref regTmp, ref regTmp); + } + + return regRes.GetInteger(sign); + } +*/ + + #endregion internal static methods + + // -------- SECTION: internal static operators -----------------* + #region internal static operators + /*public static implicit operator BigInteger(Byte value) + { + return new BigInteger(value); + } + + public static implicit operator BigInteger(SByte value) + { + return new BigInteger(value); + } + + public static implicit operator BigInteger(Int16 value) + { + return new BigInteger(value); + } + + public static implicit operator BigInteger(UInt16 value) + { + return new BigInteger(value); + } + + public static implicit operator BigInteger(int value) + { + return new BigInteger(value); + } + + public static implicit operator BigInteger(uint value) + { + return new BigInteger(value); + } + + public static implicit operator BigInteger(long value) + { + return new BigInteger(value); + } + + public static implicit operator BigInteger(ulong value) + { + return new BigInteger(value); + }*/ + + /*public static explicit operator BigInteger(Single value) + { + return new BigInteger(value); + } + + public static explicit operator BigInteger(Double value) + { + return new BigInteger(value); + } + + public static explicit operator BigInteger(Decimal value) + { + return new BigInteger(value); + } + + public static explicit operator Byte(BigInteger value) + { + return checked((byte)(int)value); + } + + public static explicit operator SByte(BigInteger value) + { + return checked((sbyte)(int)value); + } + + public static explicit operator Int16(BigInteger value) + { + return checked((short)(int)value); + } + + public static explicit operator UInt16(BigInteger value) + { + return checked((ushort)(int)value); + } + + public static explicit operator Int32(BigInteger value) + { + value.AssertValid(); + if (value._bits == null) + { + return value._sign; // value packed into int32 sign + } + else if (Length(value._bits) > 1) + { // more than 32 bits + throw new OverflowException("Overflow Int32"); + } + else if (value._sign > 0) + { + return checked((int)value._bits[0]); + } + else + { + if (value._bits[0] > kuMaskHighBit) + { // value > Int32.MinValue + throw new OverflowException("Overflow Int32"); + } + return unchecked(-(int)value._bits[0]); + } + } + + public static explicit operator UInt32(BigInteger value) + { + value.AssertValid(); + if (value._bits == null) + { + return checked((uint)value._sign); + } + else if (Length(value._bits) > 1 || value._sign < 0) + { + throw new OverflowException("Overflow UInt32"); + } + else + { + return value._bits[0]; + } + } + + public static explicit operator Int64(BigInteger value) + { + value.AssertValid(); + if (value._bits == null) + { + return value._sign; + } + + var len = Length(value._bits); + if (len > 2) + { + throw new OverflowException("Overflow Int64"); + } + + var uu = len > 1 ? NumericsHelpers.MakeUlong(value._bits[1], value._bits[0]) : value._bits[0]; + + var ll = value._sign > 0 ? (long)uu : -(long)uu; + if ((ll > 0 && value._sign > 0) || (ll < 0 && value._sign < 0)) + { + // signs match, no overflow + return ll; + } + throw new OverflowException("Overflow Int64"); + } + + public static explicit operator UInt64(BigInteger value) + { + value.AssertValid(); + if (value._bits == null) + { + return checked((ulong)value._sign); + } + + var len = Length(value._bits); + if (len > 2 || value._sign < 0) + { + throw new OverflowException("Overflow UInt64"); + } + + if (len > 1) + { + return NumericsHelpers.MakeUlong(value._bits[1], value._bits[0]); + } + else + { + return value._bits[0]; + } + }*/ + + /*public static explicit operator Single(BigInteger value) + { + return (Single)(Double)value; + }*/ + + /*public static explicit operator Double(BigInteger value) + { + value.AssertValid(); + if (value._bits == null) + return value._sign; + + ulong man; + int exp; + var sign = +1; + var reg = new BigIntegerBuilder(value, ref sign); + reg.GetApproxParts(out exp, out man); + return NumericsHelpers.GetDoubleFromParts(sign, exp, man); + } + + public static explicit operator Decimal(BigInteger value) + { + value.AssertValid(); + if (value._bits == null) + return value._sign; + + var length = Length(value._bits); + if (length > 3) throw new OverflowException("Overflow Decimal"); + + int lo = 0, mi = 0, hi = 0; + if (length > 2) hi = (Int32)value._bits[2]; + if (length > 1) mi = (Int32)value._bits[1]; + if (length > 0) lo = (Int32)value._bits[0]; + + return new Decimal(lo, mi, hi, value._sign < 0, 0); + } + + public static BigInteger operator &(BigInteger left, BigInteger right) + { + if (left.IsZero || right.IsZero) + { + return Zero; + } + + var x = left.ToUInt32Array(); + var y = right.ToUInt32Array(); + var z = new uint[Math.Max(x.Length, y.Length)]; + var xExtend = left._sign < 0 ? UInt32.MaxValue : 0; + var yExtend = right._sign < 0 ? UInt32.MaxValue : 0; + + for (var i = 0; i < z.Length; i++) + { + var xu = i < x.Length ? x[i] : xExtend; + var yu = i < y.Length ? y[i] : yExtend; + z[i] = xu & yu; + } + return new BigInteger(z); + } + + public static BigInteger operator |(BigInteger left, BigInteger right) + { + if (left.IsZero) + return right; + if (right.IsZero) + return left; + + var x = left.ToUInt32Array(); + var y = right.ToUInt32Array(); + var z = new uint[Math.Max(x.Length, y.Length)]; + var xExtend = left._sign < 0 ? UInt32.MaxValue : 0; + var yExtend = right._sign < 0 ? UInt32.MaxValue : 0; + + for (var i = 0; i < z.Length; i++) + { + var xu = i < x.Length ? x[i] : xExtend; + var yu = i < y.Length ? y[i] : yExtend; + z[i] = xu | yu; + } + return new BigInteger(z); + } + + public static BigInteger operator ^(BigInteger left, BigInteger right) + { + var x = left.ToUInt32Array(); + var y = right.ToUInt32Array(); + var z = new uint[Math.Max(x.Length, y.Length)]; + var xExtend = left._sign < 0 ? UInt32.MaxValue : 0; + var yExtend = right._sign < 0 ? UInt32.MaxValue : 0; + + for (var i = 0; i < z.Length; i++) + { + var xu = i < x.Length ? x[i] : xExtend; + var yu = i < y.Length ? y[i] : yExtend; + z[i] = xu ^ yu; + } + + return new BigInteger(z); + } + + public static BigInteger operator <<(BigInteger value, int shift) + { + + if (shift == 0) return value; + else if (shift == Int32.MinValue) return value >> Int32.MaxValue >> 1; + else if (shift < 0) return value >> -shift; + + var digitShift = shift / kcbitUint; + var smallShift = shift - digitShift * kcbitUint; + + uint[] xd; int xl; + var negx = GetPartsForBitManipulation(ref value, out xd, out xl); + + var zl = xl + digitShift + 1; + var zd = new uint[zl]; + + if (smallShift == 0) + { + for (var i = 0; i < xl; i++) + { + zd[i + digitShift] = xd[i]; + } + } + else + { + var carryShift = kcbitUint - smallShift; + uint carry = 0; + int i; + for (i = 0; i < xl; i++) + { + var rot = xd[i]; + zd[i + digitShift] = rot << smallShift | carry; + carry = rot >> carryShift; + } + zd[i + digitShift] = carry; + } + return new BigInteger(zd, negx); + } + + public static BigInteger operator >>(BigInteger value, int shift) + { + if (shift == 0) return value; + else if (shift == Int32.MinValue) return value << Int32.MaxValue << 1; + else if (shift < 0) return value << -shift; + + var digitShift = shift / kcbitUint; + var smallShift = shift - digitShift * kcbitUint; + + uint[] xd; int xl; + var negx = GetPartsForBitManipulation(ref value, out xd, out xl); + + if (negx) + { + if (shift >= kcbitUint * xl) + { + return MinusOne; + } + var temp = new uint[xl]; + Array.Copy(xd , temp , xl ); // make a copy of immutable value._bits + xd = temp; + NumericsHelpers.DangerousMakeTwosComplement(xd); // mutates xd + } + + var zl = xl - digitShift; + if (zl < 0) zl = 0; + var zd = new uint[zl]; + + if (smallShift == 0) + { + for (var i = xl - 1; i >= digitShift; i--) + { + zd[i - digitShift] = xd[i]; + } + } + else + { + var carryShift = kcbitUint - smallShift; + uint carry = 0; + for (var i = xl - 1; i >= digitShift; i--) + { + var rot = xd[i]; + if (negx && i == xl - 1) + // sign-extend the first shift for negative ints then let the carry propagate + zd[i - digitShift] = (rot >> smallShift) | (0xFFFFFFFF << carryShift); + else + zd[i - digitShift] = (rot >> smallShift) | carry; + carry = rot << carryShift; + } + } + if (negx) + { + NumericsHelpers.DangerousMakeTwosComplement(zd); // mutates zd + } + return new BigInteger(zd, negx); + } + + + public static BigInteger operator ~(BigInteger value) + { + return -(value + One); + } + + public static BigInteger operator -(BigInteger value) + { + value.AssertValid(); + value._sign = -value._sign; + value.AssertValid(); + return value; + } + + public static BigInteger operator +(BigInteger value) + { + value.AssertValid(); + return value; + } + + + public static BigInteger operator ++(BigInteger value) + { + return value + One; + } + + public static BigInteger operator --(BigInteger value) + { + return value - One; + } + + + public static BigInteger operator +(BigInteger left, BigInteger right) + { + left.AssertValid(); + right.AssertValid(); + + if (right.IsZero) return left; + if (left.IsZero) return right; + + var sign1 = +1; + var sign2 = +1; + var reg1 = new BigIntegerBuilder(left, ref sign1); + var reg2 = new BigIntegerBuilder(right, ref sign2); + + if (sign1 == sign2) + reg1.Add(ref reg2); + else + reg1.Sub(ref sign1, ref reg2); + + return reg1.GetInteger(sign1); + } + + public static BigInteger operator -(BigInteger left, BigInteger right) + { + left.AssertValid(); + right.AssertValid(); + + if (right.IsZero) return left; + if (left.IsZero) return -right; + + var sign1 = +1; + var sign2 = -1; + var reg1 = new BigIntegerBuilder(left, ref sign1); + var reg2 = new BigIntegerBuilder(right, ref sign2); + + if (sign1 == sign2) + reg1.Add(ref reg2); + else + reg1.Sub(ref sign1, ref reg2); + + return reg1.GetInteger(sign1); + } + + public static BigInteger operator *(BigInteger left, BigInteger right) + { + left.AssertValid(); + right.AssertValid(); + + var sign = +1; + var reg1 = new BigIntegerBuilder(left, ref sign); + var reg2 = new BigIntegerBuilder(right, ref sign); + + reg1.Mul(ref reg2); + return reg1.GetInteger(sign); + } + + public static BigInteger operator /(BigInteger dividend, BigInteger divisor) + { + dividend.AssertValid(); + divisor.AssertValid(); + + var sign = +1; + var regNum = new BigIntegerBuilder(dividend, ref sign); + var regDen = new BigIntegerBuilder(divisor, ref sign); + + regNum.Div(ref regDen); + return regNum.GetInteger(sign); + } + + public static BigInteger operator %(BigInteger dividend, BigInteger divisor) + { + dividend.AssertValid(); + divisor.AssertValid(); + + var signNum = +1; + var signDen = +1; + var regNum = new BigIntegerBuilder(dividend, ref signNum); + var regDen = new BigIntegerBuilder(divisor, ref signDen); + + regNum.Mod(ref regDen); + return regNum.GetInteger(signNum); + }*/ + + public static bool operator <(BigInteger left, BigInteger right) + { + return left.CompareTo(right) < 0; + } + public static bool operator <=(BigInteger left, BigInteger right) + { + return left.CompareTo(right) <= 0; + } + public static bool operator >(BigInteger left, BigInteger right) + { + return left.CompareTo(right) > 0; + } + public static bool operator >=(BigInteger left, BigInteger right) + { + return left.CompareTo(right) >= 0; + } + public static bool operator ==(BigInteger left, BigInteger right) + { + return left.Equals(right); + } + public static bool operator !=(BigInteger left, BigInteger right) + { + return !left.Equals(right); + } + + /*public static bool operator <(BigInteger left, Int64 right) + { + return left.CompareTo(right) < 0; + } + public static bool operator <=(BigInteger left, Int64 right) + { + return left.CompareTo(right) <= 0; + } + public static bool operator >(BigInteger left, Int64 right) + { + return left.CompareTo(right) > 0; + } + public static bool operator >=(BigInteger left, Int64 right) + { + return left.CompareTo(right) >= 0; + } + public static bool operator ==(BigInteger left, Int64 right) + { + return left.Equals(right); + } + public static bool operator !=(BigInteger left, Int64 right) + { + return !left.Equals(right); + } + + public static bool operator <(Int64 left, BigInteger right) + { + return right.CompareTo(left) > 0; + } + public static bool operator <=(Int64 left, BigInteger right) + { + return right.CompareTo(left) >= 0; + } + public static bool operator >(Int64 left, BigInteger right) + { + return right.CompareTo(left) < 0; + } + public static bool operator >=(Int64 left, BigInteger right) + { + return right.CompareTo(left) <= 0; + } + public static bool operator ==(Int64 left, BigInteger right) + { + return right.Equals(left); + } + public static bool operator !=(Int64 left, BigInteger right) + { + return !right.Equals(left); + } + + public static bool operator <(BigInteger left, UInt64 right) + { + return left.CompareTo(right) < 0; + } + public static bool operator <=(BigInteger left, UInt64 right) + { + return left.CompareTo(right) <= 0; + } + public static bool operator >(BigInteger left, UInt64 right) + { + return left.CompareTo(right) > 0; + } + public static bool operator >=(BigInteger left, UInt64 right) + { + return left.CompareTo(right) >= 0; + } + public static bool operator ==(BigInteger left, UInt64 right) + { + return left.Equals(right); + } + public static bool operator !=(BigInteger left, UInt64 right) + { + return !left.Equals(right); + } + + public static bool operator <(UInt64 left, BigInteger right) + { + return right.CompareTo(left) > 0; + } + public static bool operator <=(UInt64 left, BigInteger right) + { + return right.CompareTo(left) >= 0; + } + public static bool operator >(UInt64 left, BigInteger right) + { + return right.CompareTo(left) < 0; + } + public static bool operator >=(UInt64 left, BigInteger right) + { + return right.CompareTo(left) <= 0; + } + public static bool operator ==(UInt64 left, BigInteger right) + { + return right.Equals(left); + } + public static bool operator !=(UInt64 left, BigInteger right) + { + return !right.Equals(left); + }*/ + + #endregion internal static operators + + + // ----- SECTION: private serialization instance methods ---------------- + #region private serialization instance methods + #endregion private serialization instance methods + + + // ----- SECTION: internal instance utility methods ----------------* + #region internal instance utility methods + + /*private void SetBitsFromDouble(Double value) + { + int sign, exp; + ulong man; + bool fFinite; + NumericsHelpers.GetDoubleParts(value, out sign, out exp, out man, out fFinite); + Contract.Assert(sign == +1 || sign == -1); + + if (man == 0) + { + this = Zero; + return; + } + + Contract.Assert(man < 1UL << 53); + Contract.Assert(exp <= 0 || man >= 1UL << 52); + + if (exp <= 0) + { + if (exp <= -kcbitUlong) + { + this = Zero; + return; + } + this = man >> -exp; + if (sign < 0) + _sign = -_sign; + } + else if (exp <= 11) + { + this = man << exp; + if (sign < 0) + _sign = -_sign; + } + else + { + // Overflow into at least 3 uints. + // Move the leading 1 to the high bit. + man <<= 11; + exp -= 11; + + // Compute cu and cbit so that exp == 32 * cu - cbit and 0 <= cbit < 32. + var cu = (exp - 1) / kcbitUint + 1; + var cbit = cu * kcbitUint - exp; + Contract.Assert(0 <= cbit && cbit < kcbitUint); + Contract.Assert(cu >= 1); + + // Populate the uints. + _bits = new uint[cu + 2]; + _bits[cu + 1] = (uint)(man >> (cbit + kcbitUint)); + _bits[cu] = (uint)(man >> cbit); + if (cbit > 0) + _bits[cu - 1] = (uint)man << (kcbitUint - cbit); + _sign = sign; + } + }*/ + #endregion internal instance utility methods + + + // ----- SECTION: internal static utility methods ----------------* + #region internal static utility methods + //[Pure] + private static int Length(uint[] rgu) + { + var cu = rgu.Length; + if (rgu[cu - 1] != 0) + return cu; + Contract.Assert(cu >= 2 && rgu[cu - 2] != 0); + return cu - 1; + } + + internal int _Sign { get { return _sign; } } + internal uint[] _Bits { get { return _bits; } } + + +/* + internal static int BitLengthOfUInt(uint x) + { + var numBits = 0; + while (x > 0) + { + x >>= 1; + numBits++; + } + return numBits; + } +*/ + + // + // GetPartsForBitManipulation - + // + // Encapsulate the logic of normalizing the "small" and "large" forms of BigInteger + // into the "large" form so that Bit Manipulation algorithms can be simplified + // + // uint[] xd = the UInt32 array containing the entire big integer in "large" (denormalized) form + // E.g., the number one (1) and negative one (-1) are both stored as 0x00000001 + // BigInteger values Int32.MinValue < x <= Int32.MaxValue are converted to this + // format for convenience. + // int xl = the length of xd + // return bool = true for negative numbers + // + /*private static bool GetPartsForBitManipulation(ref BigInteger x, out uint[] xd, out int xl) + { + if (x._bits == null) + { + xd = x._sign < 0 ? new[] { (uint)-x._sign } : new[] { (uint)x._sign }; + } + else + { + xd = x._bits; + } + xl = x._bits == null ? 1 : x._bits.Length; + return x._sign < 0; + }*/ + + // Gets an upper bound on the product of uHiRes * (2^32)^(cuRes-1) and uHiMul * (2^32)^(cuMul-1). + // The result is put int uHiRes and cuRes. +/* + private static void MulUpper(ref uint uHiRes, ref int cuRes, uint uHiMul, int cuMul) + { + var uu = (ulong)uHiRes * uHiMul; + var uHi = NumericsHelpers.GetHi(uu); + if (uHi != 0) + { + if (NumericsHelpers.GetLo(uu) != 0 && ++uHi == 0) + { + uHi = 1; + cuRes++; + } + uHiRes = uHi; + cuRes += cuMul; + } + else + { + uHiRes = NumericsHelpers.GetLo(uu); + cuRes += cuMul - 1; + } + } +*/ + + // Gets a lower bound on the product of uHiRes * (2^32)^(cuRes-1) and uHiMul * (2^32)^(cuMul-1). + // The result is put int uHiRes and cuRes. +/* + private static void MulLower(ref uint uHiRes, ref int cuRes, uint uHiMul, int cuMul) + { + var uu = (ulong)uHiRes * uHiMul; + var uHi = NumericsHelpers.GetHi(uu); + if (uHi != 0) + { + uHiRes = uHi; + cuRes += cuMul; + } + else + { + uHiRes = NumericsHelpers.GetLo(uu); + cuRes += cuMul - 1; + } + } +*/ + + private static int GetDiffLength(uint[] rgu1, uint[] rgu2, int cu) + { + for (var iv = cu; --iv >= 0; ) + { + if (rgu1[iv] != rgu2[iv]) + return iv + 1; + } + return 0; + } + #endregion internal static utility methods + } +}
\ No newline at end of file diff --git a/runtime/VMProtect.Runtime/Numerics/BigIntegerBuilder.cs b/runtime/VMProtect.Runtime/Numerics/BigIntegerBuilder.cs new file mode 100644 index 0000000..02ec6aa --- /dev/null +++ b/runtime/VMProtect.Runtime/Numerics/BigIntegerBuilder.cs @@ -0,0 +1,1529 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== + +using System; + +using Contracts = System.Diagnostics.Debug; +using Contract = System.Diagnostics.Debug; +using Conditional = System.Diagnostics.ConditionalAttribute; + +// ReSharper disable once CheckNamespace +namespace Numerics +{ + /// <summary> + /// BigIntegerBuilder holds a multiprecision unsigned integer value. It is mutable and + /// supports common arithmetic operations. Be careful NOT to simply assign one + /// BigIntegerBuilder to another, unless you really know what you are doing. The proper + /// way to replicate a BigIntegerBuilder is via the constructor "BigIntegerBuilder(ref BigIntegerBuilder reg)", + /// or with reg1.Load(ref reg2). Using the ctor marks the buffer as shared so changing the + /// value of one register will not affect the other. Using Load copies the contents from + /// one to the other. Either way, the internal buffer isn't aliased incorrectly. + /// </summary> + internal struct BigIntegerBuilder + { + // ReSharper disable once InconsistentNaming + private const int kcbitUint = 32; + + // For a single uint, _iuLast is 0. + private int _iuLast; + + // Used if _iuLast == 0. + private uint _uSmall; + + // Used if _iuLast > 0. + private uint[] _rgu; + + // This is false whenever _rgu is null or is shared with a NewBigInteger + // or with another BigIntegerBuilder. + private bool _fWritable; + + [Conditional("DEBUG")] + // ReSharper disable once UnusedParameter.Local + private void AssertValid(bool fTrimmed) + { + if (_iuLast <= 0) + { + Contract.Assert(_iuLast == 0); + Contract.Assert(!_fWritable || _rgu != null); + } + else + { + Contract.Assert(_rgu != null && _rgu.Length > _iuLast); + Contract.Assert(!fTrimmed || _rgu[_iuLast] != 0); + } + } + +#if CONTRACTS_FULL + [ContractInvariantMethod] + private void ObjectInvariant() + { + Contract.Invariant(_iuLast >=0); + Contract.Invariant(!(_iuLast == 0) || (!_fWritable || _rgu != null)); + Contract.Invariant(!(_iuLast > 0) || (_rgu != null && _rgu.Length > _iuLast)); + } +#endif + +/* + internal BigIntegerBuilder(ref BigIntegerBuilder reg) + { + reg.AssertValid(true); + this = reg; + if (_fWritable) + { + _fWritable = false; + if (_iuLast == 0) + _rgu = null; + else + reg._fWritable = false; + } + AssertValid(true); + } +*/ + + internal BigIntegerBuilder(int cuAlloc) + { + _iuLast = 0; + _uSmall = 0; + if (cuAlloc > 1) + { + _rgu = new uint[cuAlloc]; + _fWritable = true; + } + else + { + _rgu = null; + _fWritable = false; + } + AssertValid(true); + } + +/* + internal BigIntegerBuilder(BigInteger bn) + { + _fWritable = false; + _rgu = bn._Bits; + if (_rgu == null) + { + _iuLast = 0; + _uSmall = NumericsHelpers.Abs(bn._Sign); + } + else + { + _iuLast = _rgu.Length - 1; + _uSmall = _rgu[0]; + while (_iuLast > 0 && _rgu[_iuLast] == 0) + --_iuLast; + } + AssertValid(true); + } +*/ + + internal BigIntegerBuilder(BigInteger bn, ref int sign) + { + Contract.Assert(sign == +1 || sign == -1); + + _fWritable = false; + _rgu = bn._Bits; + int n = bn._Sign; + int mask = n >> (kcbitUint - 1); + sign = (sign ^ mask) - mask; + if (_rgu == null) + { + _iuLast = 0; + _uSmall = (uint)((n ^ mask) - mask); + } + else + { + _iuLast = _rgu.Length - 1; + _uSmall = _rgu[0]; + while (_iuLast > 0 && _rgu[_iuLast] == 0) + --_iuLast; + } + AssertValid(true); + } + + internal BigInteger GetInteger(int sign) + { + Contract.Assert(sign == +1 || sign == -1); + AssertValid(true); + + uint[] bits; + GetIntegerParts(sign, out sign, out bits); + return new BigInteger(sign, bits); + } + + private void GetIntegerParts(int signSrc, out int sign, out uint[] bits) + { + Contract.Assert(signSrc == +1 || signSrc == -1); + AssertValid(true); + + if (_iuLast == 0) + { + if (_uSmall <= int.MaxValue) + { + sign = signSrc * (int)_uSmall; + bits = null; + return; + } + if (_rgu == null) + _rgu = new[] { _uSmall }; + else if (_fWritable) + _rgu[0] = _uSmall; + else if (_rgu[0] != _uSmall) + _rgu = new[] { _uSmall }; + } + + // The sign is +/- 1. + sign = signSrc; + + int cuExtra = _rgu.Length - _iuLast - 1; + Contract.Assert(cuExtra >= 0); + if (cuExtra <= 1) + { + if (cuExtra == 0 || _rgu[_iuLast + 1] == 0) + { + _fWritable = false; + bits = _rgu; + return; + } + if (_fWritable) + { + _rgu[_iuLast + 1] = 0; + _fWritable = false; + bits = _rgu; + return; + } + // The buffer isn't writable, but has an extra uint that is non-zero, + // so we have to allocate a new buffer. + } + + // Keep the bigger buffer (if it is writable), but create a smaller one for the BigInteger. + bits = _rgu; + Array.Resize(ref bits, _iuLast + 1); + if (!_fWritable) + _rgu = bits; + } + + private void Set(uint u) + { + _uSmall = u; + _iuLast = 0; + AssertValid(true); + } + + private void Set(ulong uu) + { + uint uHi = NumericsHelpers.GetHi(uu); + if (uHi == 0) + { + _uSmall = NumericsHelpers.GetLo(uu); + _iuLast = 0; + } + else + { + SetSizeLazy(2); + _rgu[0] = (uint) uu; + _rgu[1] = uHi; + } + } + + internal int Size { get { return _iuLast + 1; } } + + //internal uint High { get { return _iuLast == 0 ? _uSmall : _rgu[_iuLast]; } } + + + /*internal void GetApproxParts(out int exp, out ulong man) + { + AssertValid(true); + if (_iuLast == 0) + { + man = _uSmall; + exp = 0; + return; + } + + int cuLeft = _iuLast - 1; + man = NumericsHelpers.MakeUlong(_rgu[cuLeft + 1], _rgu[cuLeft]); + exp = cuLeft * kcbitUint; + + int cbit; + if (cuLeft > 0 && (cbit = NumericsHelpers.CbitHighZero(_rgu[cuLeft + 1])) > 0) + { + // Get 64 bits. + Contract.Assert(cbit < kcbitUint); + man = (man << cbit) | (_rgu[cuLeft - 1] >> (kcbitUint - cbit)); + exp -= cbit; + } + }*/ + + private void Trim() + { + AssertValid(false); + if (_iuLast > 0 && _rgu[_iuLast] == 0) + { + _uSmall = _rgu[0]; + while (--_iuLast > 0 && _rgu[_iuLast] == 0) + { + } + } + AssertValid(true); + } + + private int CuNonZero + { + get + { + Contract.Assert(_iuLast > 0); + int cu = 0; + for (int iu = _iuLast; iu >= 0; --iu) + { + if (_rgu[iu] != 0) + cu++; + } + return cu; + } + } + + // Sets the size to cu and makes sure the buffer is writable (if cu > 1), + // but makes no guarantees about the contents of the buffer. + private void SetSizeLazy(int cu) + { + Contract.Assert(cu > 0); + AssertValid(false); + if (cu <= 1) + { + _iuLast = 0; + return; + } + if (!_fWritable || _rgu.Length < cu) + { + _rgu = new uint[cu]; + _fWritable = true; + } + _iuLast = cu - 1; + AssertValid(false); + } + + // Sets the size to cu, makes sure the buffer is writable (if cu > 1), + // and set the contents to all zero. + private void SetSizeClear(int cu) + { + Contract.Assert(cu > 0); + AssertValid(false); + if (cu <= 1) + { + _iuLast = 0; + _uSmall = 0; + return; + } + if (!_fWritable || _rgu.Length < cu) + { + _rgu = new uint[cu]; + _fWritable = true; + } + else + Array.Clear(_rgu, 0, cu); + _iuLast = cu - 1; + AssertValid(false); + } + + // Sets the size to cu, makes sure the buffer is writable (if cu > 1), + // and maintains the contents. If the buffer is reallocated, cuExtra + // uints are also allocated. + private void SetSizeKeep(int cu, int cuExtra) + { + Contract.Assert(cu > 0 && cuExtra >= 0); + AssertValid(false); + + if (cu <= 1) + { + if (_iuLast > 0) + _uSmall = _rgu[0]; + _iuLast = 0; + return; + } + if (!_fWritable || _rgu.Length < cu) + { + uint[] rgu = new uint[cu + cuExtra]; + if (_iuLast == 0) + rgu[0] = _uSmall; + else + Array.Copy(_rgu, rgu, Math.Min(cu, _iuLast + 1)); + _rgu = rgu; + _fWritable = true; + } + else if (_iuLast + 1 < cu) + { + Array.Clear(_rgu, _iuLast + 1, cu - _iuLast - 1); + if (_iuLast == 0) + _rgu[0] = _uSmall; + } + _iuLast = cu - 1; + AssertValid(false); + } + + // Makes sure the buffer is writable and can support cu uints. + // Preserves the contents of the buffer up to min(_iuLast + 1, cu). + // Changes the size if cu <= _iuLast and the buffer needs to be allocated. +/* + internal void EnsureWritable(int cu, int cuExtra) + { + Contract.Assert(cu > 1 && cuExtra >= 0); + AssertValid(false); + + if (_fWritable && _rgu.Length >= cu) + return; + + uint[] rgu = new uint[cu + cuExtra]; + if (_iuLast > 0) + { + if (_iuLast >= cu) + _iuLast = cu - 1; + Array.Copy(_rgu, rgu, _iuLast + 1); + } + _rgu = rgu; + _fWritable = true; + AssertValid(false); + } +*/ + + // Makes sure the buffer is writable and can support _iuLast + 1 uints. + // Preserves the contents of the buffer. + private void EnsureWritable(int cuExtra = 0) + { + Contract.Assert(cuExtra >= 0); + AssertValid(false); + Contract.Assert(_iuLast > 0); + + if (_fWritable) + return; + + uint[] rgu = new uint[_iuLast + 1 + cuExtra]; + Array.Copy(_rgu, rgu, _iuLast + 1); + _rgu = rgu; + _fWritable = true; + AssertValid(false); + } + + // Loads the value of reg into this register. + /*internal void Load(ref BigIntegerBuilder reg) + { + Load(ref reg, 0); + }*/ + + // Loads the value of reg into this register. If we need to allocate memory + // to perform the load, allocate cuExtra elements. + private void Load(ref BigIntegerBuilder reg, int cuExtra) + { + Contract.Assert(cuExtra >= 0); + AssertValid(false); + reg.AssertValid(true); + + if (reg._iuLast == 0) + { + _uSmall = reg._uSmall; + _iuLast = 0; + } + else + { + if (!_fWritable || _rgu.Length <= reg._iuLast) + { + _rgu = new uint[reg._iuLast + 1 + cuExtra]; + _fWritable = true; + } + _iuLast = reg._iuLast; + Array.Copy(reg._rgu, _rgu, _iuLast + 1); + } + AssertValid(true); + } + + /*internal void Add(uint u) + { + AssertValid(true); + if (_iuLast == 0) + { + if ((_uSmall += u) >= u) + return; + SetSizeLazy(2); + _rgu[0] = _uSmall; + _rgu[1] = 1; + return; + } + + if (u == 0) + return; + + uint uNew = _rgu[0] + u; + if (uNew < u) + { + // Have carry. + EnsureWritable(1); + ApplyCarry(1); + } + else if (!_fWritable) + EnsureWritable(); + _rgu[0] = uNew; + AssertValid(true); + } + + internal void Add(ref BigIntegerBuilder reg) + { + AssertValid(true); + reg.AssertValid(true); + + if (reg._iuLast == 0) + { + Add(reg._uSmall); + return; + } + if (_iuLast == 0) + { + uint u = _uSmall; + if (u == 0) + this = new BigIntegerBuilder(ref reg); + else + { + Load(ref reg, 1); + Add(u); + } + return; + } + + EnsureWritable(Math.Max(_iuLast, reg._iuLast) + 1, 1); + + int cuAdd = reg._iuLast + 1; + if (_iuLast < reg._iuLast) + { + cuAdd = _iuLast + 1; + Array.Copy(reg._rgu, _iuLast + 1, _rgu, _iuLast + 1, reg._iuLast - _iuLast); + Contract.Assert(_iuLast > 0); + _iuLast = reg._iuLast; + } + + // Add, tracking carry. + uint uCarry = 0; + for (int iu = 0; iu < cuAdd; iu++) + { + uCarry = AddCarry(ref _rgu[iu], reg._rgu[iu], uCarry); + Contract.Assert(uCarry <= 1); + } + + // Deal with extra carry. + if (uCarry != 0) + ApplyCarry(cuAdd); + AssertValid(true); + } + + internal void Sub(ref int sign, uint u) + { + Contract.Assert(sign == +1 || sign == -1); + AssertValid(true); + if (_iuLast == 0) + { + if (u <= _uSmall) + _uSmall -= u; + else + { + _uSmall = u - _uSmall; + sign = -sign; + } + AssertValid(true); + return; + } + + if (u == 0) + return; + + EnsureWritable(); + + uint uTmp = _rgu[0]; + _rgu[0] = uTmp - u; + if (uTmp < u) + { + ApplyBorrow(1); + Trim(); + } + AssertValid(true); + } + + internal void Sub(ref int sign, ref BigIntegerBuilder reg) + { + Contract.Assert(sign == +1 || sign == -1); + AssertValid(true); + reg.AssertValid(true); + + if (reg._iuLast == 0) + { + Sub(ref sign, reg._uSmall); + return; + } + if (_iuLast == 0) + { + uint u = _uSmall; + if (u == 0) + this = new BigIntegerBuilder(ref reg); + else + { + Load(ref reg); + Sub(ref sign, u); + } + sign = -sign; + return; + } + + if (_iuLast < reg._iuLast) + { + SubRev(ref reg); + sign = -sign; + return; + } + + int cuSub = reg._iuLast + 1; + if (_iuLast == reg._iuLast) + { + // Determine which is larger. + _iuLast = BigInteger.GetDiffLength(_rgu, reg._rgu, _iuLast + 1) - 1; + if (_iuLast < 0) + { + _iuLast = 0; + _uSmall = 0; + return; + } + + uint u1 = _rgu[_iuLast]; + uint u2 = reg._rgu[_iuLast]; + if (_iuLast == 0) + { + if (u1 < u2) + { + _uSmall = u2 - u1; + sign = -sign; + } + else + _uSmall = u1 - u2; + AssertValid(true); + return; + } + + if (u1 < u2) + { + Contract.Assert(_iuLast > 0); + reg._iuLast = _iuLast; + SubRev(ref reg); + reg._iuLast = cuSub - 1; + Contract.Assert(reg._iuLast > 0); + sign = -sign; + return; + } + cuSub = _iuLast + 1; + } + + EnsureWritable(); + + // Subtract, tracking borrow. + uint uBorrow = 0; + for (int iu = 0; iu < cuSub; iu++) + { + uBorrow = SubBorrow(ref _rgu[iu], reg._rgu[iu], uBorrow); + Contract.Assert(uBorrow <= 1); + } + if (uBorrow != 0) + { + Contract.Assert(uBorrow == 1 && cuSub <= _iuLast); + ApplyBorrow(cuSub); + } + Trim(); + } + + // Subtract this register from the given one and put the result in this one. + // Asserts that reg is larger in the most significant uint. + private void SubRev(ref BigIntegerBuilder reg) + { + Contract.Assert(0 < _iuLast && _iuLast <= reg._iuLast); + Contract.Assert(_iuLast < reg._iuLast || _rgu[_iuLast] < reg._rgu[_iuLast]); + + EnsureWritable(reg._iuLast + 1, 0); + + int cuSub = _iuLast + 1; + if (_iuLast < reg._iuLast) + { + Array.Copy(reg._rgu, _iuLast + 1, _rgu, _iuLast + 1, reg._iuLast - _iuLast); + Contract.Assert(_iuLast > 0); + _iuLast = reg._iuLast; + } + + uint uBorrow = 0; + for (int iu = 0; iu < cuSub; iu++) + { + uBorrow = SubRevBorrow(ref _rgu[iu], reg._rgu[iu], uBorrow); + Contract.Assert(uBorrow <= 1); + } + if (uBorrow != 0) + { + Contract.Assert(uBorrow == 1); + ApplyBorrow(cuSub); + } + Trim(); + }*/ + + private void Mul(uint u) + { + if (u == 0) + { + Set(0); + return; + } + if (u == 1) + return; + + if (_iuLast == 0) + { + Set((ulong)_uSmall * u); + return; + } + + EnsureWritable(1); + + uint uCarry = 0; + for (int iu = 0; iu <= _iuLast; iu++) + uCarry = MulCarry(ref _rgu[iu], u, uCarry); + + if (uCarry != 0) + { + SetSizeKeep(_iuLast + 2, 0); + _rgu[_iuLast] = uCarry; + } + } + + // This version may share memory with regMul. + /*internal void Mul(ref BigIntegerBuilder regMul) + { + AssertValid(true); + regMul.AssertValid(true); + + if (regMul._iuLast == 0) + Mul(regMul._uSmall); + else if (_iuLast == 0) + { + uint u = _uSmall; + if (u == 1) + this = new BigIntegerBuilder(ref regMul); + else if (u != 0) + { + Load(ref regMul, 1); + Mul(u); + } + } + else + { + int cuBase = _iuLast + 1; + SetSizeKeep(cuBase + regMul._iuLast, 1); + + for (int iu = cuBase; --iu >= 0; ) + { + uint uMul = _rgu[iu]; + _rgu[iu] = 0; + uint uCarry = 0; + for (int iuSrc = 0; iuSrc <= regMul._iuLast; iuSrc++) + uCarry = AddMulCarry(ref _rgu[iu + iuSrc], regMul._rgu[iuSrc], uMul, uCarry); + if (uCarry != 0) + { + for (int iuDst = iu + regMul._iuLast + 1; uCarry != 0 && iuDst <= _iuLast; iuDst++) + uCarry = AddCarry(ref _rgu[iuDst], 0, uCarry); + if (uCarry != 0) + { + SetSizeKeep(_iuLast + 2, 0); + _rgu[_iuLast] = uCarry; + } + } + } + AssertValid(true); + } + }*/ + + // Multiply reg1 times reg2, putting the result in 'this'. This version never shares memory + // with either of the operands. This is useful when performing a series of arithmetic operations + // and large working buffers are allocated up front. + internal void Mul(ref BigIntegerBuilder reg1, ref BigIntegerBuilder reg2) + { + AssertValid(true); + reg1.AssertValid(true); + reg2.AssertValid(true); + + if (reg1._iuLast == 0) + { + if (reg2._iuLast == 0) + Set((ulong)reg1._uSmall * reg2._uSmall); + else + { + Load(ref reg2, 1); + Mul(reg1._uSmall); + } + } + else if (reg2._iuLast == 0) + { + Load(ref reg1, 1); + Mul(reg2._uSmall); + } + else + { + Contract.Assert(reg1._iuLast > 0 && reg2._iuLast > 0); + SetSizeClear(reg1._iuLast + reg2._iuLast + 2); + + uint[] rgu1, rgu2; + int cu1, cu2; + + // We prefer more iterations on the inner loop and fewer on the outer. + if (reg1.CuNonZero <= reg2.CuNonZero) + { + rgu1 = reg1._rgu; cu1 = reg1._iuLast + 1; + rgu2 = reg2._rgu; cu2 = reg2._iuLast + 1; + } + else + { + rgu1 = reg2._rgu; cu1 = reg2._iuLast + 1; + rgu2 = reg1._rgu; cu2 = reg1._iuLast + 1; + } + + for (int iu1 = 0; iu1 < cu1; iu1++) + { + uint uCur = rgu1[iu1]; + if (uCur == 0) + continue; + + uint uCarry = 0; + int iuRes = iu1; + for (int iu2 = 0; iu2 < cu2; iu2++, iuRes++) + uCarry = AddMulCarry(ref _rgu[iuRes], uCur, rgu2[iu2], uCarry); + while (uCarry != 0) + uCarry = AddCarry(ref _rgu[iuRes++], 0, uCarry); + } + Trim(); + } + } + + // Divide 'this' by uDen, leaving the quotient in 'this' and returning the remainder. + /*internal uint DivMod(uint uDen) + { + AssertValid(true); + + if (uDen == 1) + return 0; + if (_iuLast == 0) + { + uint uTmp = _uSmall; + _uSmall = uTmp / uDen; + return uTmp % uDen; + } + + EnsureWritable(); + + ulong uu = 0; + for (int iv = _iuLast; iv >= 0; iv--) + { + uu = NumericsHelpers.MakeUlong((uint)uu, _rgu[iv]); + _rgu[iv] = (uint)(uu / uDen); + uu %= uDen; + } + Trim(); + return (uint)uu; + }*/ + + // Divide regNum by uDen, returning the remainder and tossing the quotient. + private static uint Mod(ref BigIntegerBuilder regNum, uint uDen) + { + regNum.AssertValid(true); + + if (uDen == 1) + return 0; + if (regNum._iuLast == 0) + return regNum._uSmall % uDen; + + ulong uu = 0; + for (int iv = regNum._iuLast; iv >= 0; iv--) + { + uu = NumericsHelpers.MakeUlong((uint)uu, regNum._rgu[iv]); + uu %= uDen; + } + return (uint)uu; + } + + // Divide 'this' by regDen, leaving the remainder in 'this' and tossing the quotient. + internal void Mod(ref BigIntegerBuilder regDen) + { + AssertValid(true); + regDen.AssertValid(true); + + if (regDen._iuLast == 0) + { + Set(Mod(ref this, regDen._uSmall)); + return; + } + if (_iuLast == 0) + return; + + BigIntegerBuilder regTmp = new BigIntegerBuilder(); + ModDivCore(ref this, ref regDen, false, ref regTmp); + } + + // Divide 'this' by regDen, leaving the quotient in 'this' and tossing the remainder. + /*internal void Div(ref BigIntegerBuilder regDen) + { + AssertValid(true); + regDen.AssertValid(true); + + if (regDen._iuLast == 0) + { + DivMod(regDen._uSmall); + return; + } + if (_iuLast == 0) + { + _uSmall = 0; + return; + } + + BigIntegerBuilder regTmp = new BigIntegerBuilder(); + ModDivCore(ref this, ref regDen, true, ref regTmp); + NumericsHelpers.Swap(ref this, ref regTmp); + }*/ + + // Divide regNum by regDen, leaving the remainder in regNum and the quotient in regQuo (if fQuo is true). +/* + internal void ModDiv(ref BigIntegerBuilder regDen, ref BigIntegerBuilder regQuo) + { + if (regDen._iuLast == 0) + { + regQuo.Set(DivMod(regDen._uSmall)); + NumericsHelpers.Swap(ref this, ref regQuo); + return; + } + if (_iuLast == 0) + return; + + ModDivCore(ref this, ref regDen, true, ref regQuo); + } +*/ + + private static void ModDivCore(ref BigIntegerBuilder regNum, ref BigIntegerBuilder regDen, bool fQuo, ref BigIntegerBuilder regQuo) + { + Contract.Assert(regNum._iuLast > 0 && regDen._iuLast > 0); + + regQuo.Set(0); + if (regNum._iuLast < regDen._iuLast) + return; + + Contract.Assert(0 < regDen._iuLast && regDen._iuLast <= regNum._iuLast); + int cuDen = regDen._iuLast + 1; + int cuDiff = regNum._iuLast - regDen._iuLast; + + // Determine whether the result will have cuDiff "digits" or cuDiff+1 "digits". + int cuQuo = cuDiff; + for (int iu = regNum._iuLast; ; iu--) + { + if (iu < cuDiff) + { + cuQuo++; + break; + } + if (regDen._rgu[iu - cuDiff] != regNum._rgu[iu]) + { + if (regDen._rgu[iu - cuDiff] < regNum._rgu[iu]) + cuQuo++; + break; + } + } + + if (cuQuo == 0) + return; + + if (fQuo) + regQuo.SetSizeLazy(cuQuo); + + // Get the uint to use for the trial divisions. We normalize so the high bit is set. + uint uDen = regDen._rgu[cuDen - 1]; + uint uDenNext = regDen._rgu[cuDen - 2]; + int cbitShiftLeft = NumericsHelpers.CbitHighZero(uDen); + int cbitShiftRight = kcbitUint - cbitShiftLeft; + if (cbitShiftLeft > 0) + { + uDen = (uDen << cbitShiftLeft) | (uDenNext >> cbitShiftRight); + uDenNext <<= cbitShiftLeft; + if (cuDen > 2) + uDenNext |= regDen._rgu[cuDen - 3] >> cbitShiftRight; + } + Contract.Assert((uDen & 0x80000000) != 0); + + // Allocate and initialize working space. + Contract.Assert(cuQuo + cuDen == regNum._iuLast + 1 || cuQuo + cuDen == regNum._iuLast + 2); + regNum.EnsureWritable(); + + for (int iu = cuQuo; --iu >= 0; ) + { + // Get the high (normalized) bits of regNum. + uint uNumHi = iu + cuDen <= regNum._iuLast ? regNum._rgu[iu + cuDen] : 0; + Contract.Assert(uNumHi <= regDen._rgu[cuDen - 1]); + + ulong uuNum = NumericsHelpers.MakeUlong(uNumHi, regNum._rgu[iu + cuDen - 1]); + uint uNumNext = regNum._rgu[iu + cuDen - 2]; + if (cbitShiftLeft > 0) + { + uuNum = (uuNum << cbitShiftLeft) | (uNumNext >> cbitShiftRight); + uNumNext <<= cbitShiftLeft; + if (iu + cuDen >= 3) + uNumNext |= regNum._rgu[iu + cuDen - 3] >> cbitShiftRight; + } + + // Divide to get the quotient digit. + ulong uuQuo = uuNum / uDen; + ulong uuRem = (uint)(uuNum % uDen); + Contract.Assert(uuQuo <= (ulong)uint.MaxValue + 2); + if (uuQuo > uint.MaxValue) + { + uuRem += uDen * (uuQuo - uint.MaxValue); + uuQuo = uint.MaxValue; + } + while (uuRem <= uint.MaxValue && uuQuo * uDenNext > NumericsHelpers.MakeUlong((uint)uuRem, uNumNext)) + { + uuQuo--; + uuRem += uDen; + } + + // Multiply and subtract. Note that uuQuo may be 1 too large. If we have a borrow + // at the end, we'll add the denominator back on and decrement uuQuo. + if (uuQuo > 0) + { + ulong uuBorrow = 0; + for (int iu2 = 0; iu2 < cuDen; iu2++) + { + uuBorrow += regDen._rgu[iu2] * uuQuo; + uint uSub = (uint)uuBorrow; + uuBorrow >>= kcbitUint; + if (regNum._rgu[iu + iu2] < uSub) + uuBorrow++; + regNum._rgu[iu + iu2] -= uSub; + } + + Contract.Assert(uNumHi == uuBorrow || uNumHi == uuBorrow - 1); + if (uNumHi < uuBorrow) + { + // Add, tracking carry. + uint uCarry = 0; + for (int iu2 = 0; iu2 < cuDen; iu2++) + { + uCarry = AddCarry(ref regNum._rgu[iu + iu2], regDen._rgu[iu2], uCarry); + Contract.Assert(uCarry <= 1); + } + Contract.Assert(uCarry == 1); + uuQuo--; + } + regNum._iuLast = iu + cuDen - 1; + } + + if (fQuo) + { + if (cuQuo == 1) + regQuo._uSmall = (uint)uuQuo; + else + regQuo._rgu[iu] = (uint)uuQuo; + } + } + + Contract.Assert(cuDen > 1 && regNum._iuLast > 0); + regNum._iuLast = cuDen - 1; + regNum.Trim(); + } + + //private static readonly double kdblLn2To32 = 32 * Math.Log(2); + + /*internal void ShiftRight(int cbit) + { + AssertValid(true); + if (cbit <= 0) + { + if (cbit < 0) + ShiftLeft(-cbit); + return; + } + ShiftRight(cbit / kcbitUint, cbit % kcbitUint); + } + + internal void ShiftRight(int cuShift, int cbitShift) + { + Contract.Assert(cuShift >= 0); + Contract.Assert(0 <= cbitShift); + Contract.Assert(cbitShift < kcbitUint); + AssertValid(true); + + if ((cuShift | cbitShift) == 0) + return; + if (cuShift > _iuLast) + { + Set(0); + return; + } + if (_iuLast == 0) + { + _uSmall >>= cbitShift; + AssertValid(true); + return; + } + + uint[] rguSrc = _rgu; + int cuSrc = _iuLast + 1; + _iuLast -= cuShift; + if (_iuLast == 0) + _uSmall = rguSrc[cuShift] >> cbitShift; + else + { + Contract.Assert(_rgu.Length > _iuLast); + if (!_fWritable) + { + _rgu = new uint[_iuLast + 1]; + _fWritable = true; + } + if (cbitShift > 0) + { + for (int iuSrc = cuShift + 1, iuDst = 0; iuSrc < cuSrc; iuSrc++, iuDst++) + _rgu[iuDst] = (rguSrc[iuSrc - 1] >> cbitShift) | (rguSrc[iuSrc] << (kcbitUint - cbitShift)); + _rgu[_iuLast] = rguSrc[cuSrc - 1] >> cbitShift; + Trim(); + } + else + Array.Copy(rguSrc, cuShift, _rgu, 0, _iuLast + 1); + } + AssertValid(true); + }*/ + + /*internal void ShiftLeft(int cbit) + { + AssertValid(true); + if (cbit <= 0) + { + if (cbit < 0) + ShiftRight(-cbit); + return; + } + ShiftLeft(cbit / kcbitUint, cbit % kcbitUint); + } + + internal void ShiftLeft(int cuShift, int cbitShift) + { + Contract.Assert(cuShift >= 0); + Contract.Assert(0 <= cbitShift); + Contract.Assert(cbitShift < kcbitUint); + AssertValid(true); + + int iuLastNew = _iuLast + cuShift; + uint uHigh = 0; + if (cbitShift > 0) + { + uHigh = High >> (kcbitUint - cbitShift); + if (uHigh != 0) + iuLastNew++; + } + if (iuLastNew == 0) + { + _uSmall <<= cbitShift; + return; + } + + uint[] rguSrc = _rgu; + bool fClearLow = cuShift > 0; + if (!_fWritable || _rgu.Length <= iuLastNew) + { + _rgu = new uint[iuLastNew + 1]; + _fWritable = true; + fClearLow = false; + } + if (_iuLast == 0) + { + if (uHigh != 0) + _rgu[cuShift + 1] = uHigh; + _rgu[cuShift] = _uSmall << cbitShift; + } + else if (cbitShift == 0) + Array.Copy(rguSrc, 0, _rgu, cuShift, _iuLast + 1); + else + { + int iuSrc = _iuLast; + int iuDst = _iuLast + cuShift; + if (iuDst < iuLastNew) + _rgu[iuLastNew] = uHigh; + for (; iuSrc > 0; iuSrc--, iuDst--) + _rgu[iuDst] = (rguSrc[iuSrc] << cbitShift) | (rguSrc[iuSrc - 1] >> (kcbitUint - cbitShift)); + _rgu[cuShift] = rguSrc[0] << cbitShift; + } + _iuLast = iuLastNew; + if (fClearLow) + Array.Clear(_rgu, 0, cuShift); + }*/ + + // Get the high two uints, combined into a ulong, zero extending to + // length cu if necessary. Asserts cu > _iuLast and _iuLast > 0. +/* + private ulong GetHigh2(int cu) + { + Contract.Assert(cu >= 2); + Contract.Assert(_iuLast > 0); + Contract.Assert(cu > _iuLast); + + if (cu - 1 <= _iuLast) + return NumericsHelpers.MakeUlong(_rgu[cu - 1], _rgu[cu - 2]); + if (cu - 2 == _iuLast) + return _rgu[cu - 2]; + return 0; + } +*/ + + // Apply a single carry starting at iu, extending the register + // if needed. +/* + private void ApplyCarry(int iu) + { + Contract.Assert(0 <= iu); + Contract.Assert(_fWritable && _iuLast > 0); + Contract.Assert(iu <= _iuLast + 1); + + for (; ; iu++) + { + if (iu > _iuLast) + { + if (_iuLast + 1 == _rgu.Length) + Array.Resize(ref _rgu, _iuLast + 2); + _rgu[++_iuLast] = 1; + break; + } + if (++_rgu[iu] > 0) + break; + } + } +*/ + + // Apply a single borrow starting at iu. This does NOT trim the result. +/* + private void ApplyBorrow(int iuMin) + { + Contract.Assert(0 < iuMin); + Contract.Assert(_fWritable && _iuLast > 0); + Contract.Assert(iuMin <= _iuLast); + + for (int iu = iuMin; iu <= _iuLast; iu++) + { + uint u = _rgu[iu]--; + if (u > 0) + return; + } + // Borrowed off the end! + Contract.Assert(false, "Invalid call to ApplyBorrow"); + } +*/ + + private static uint AddCarry(ref uint u1, uint u2, uint uCarry) + { + ulong uu = (ulong)u1 + u2 + uCarry; + u1 = (uint)uu; + return (uint)(uu >> kcbitUint); + } + + /*private static uint SubBorrow(ref uint u1, uint u2, uint uBorrow) + { + ulong uu = (ulong)u1 - u2 - uBorrow; + u1 = (uint)uu; + return (uint)-(int)(uu >> kcbitUint); + } + + private static uint SubRevBorrow(ref uint u1, uint u2, uint uBorrow) + { + ulong uu = (ulong)u2 - u1 - uBorrow; + u1 = (uint)uu; + return (uint)-(int)(uu >> kcbitUint); + }*/ + + private static uint MulCarry(ref uint u1, uint u2, uint uCarry) + { + // This is guaranteed not to overflow. + ulong uuRes = (ulong)u1 * u2 + uCarry; + u1 = (uint)uuRes; + return (uint)(uuRes >> kcbitUint); + } + + private static uint AddMulCarry(ref uint uAdd, uint uMul1, uint uMul2, uint uCarry) + { + // This is guaranteed not to overflow. + ulong uuRes = (ulong)uMul1 * uMul2 + uAdd + uCarry; + uAdd = (uint)uuRes; + return (uint)(uuRes >> kcbitUint); + } + + // ReSharper disable once InconsistentNaming +/* + internal static void GCD(ref BigIntegerBuilder reg1, ref BigIntegerBuilder reg2) + { + // Use Lehmer's GCD, with improvements, after eliminating common powers of 2. + if (reg1._iuLast > 0 && reg1._rgu[0] == 0 || reg2._iuLast > 0 && reg2._rgu[0] == 0) + { + int cbit1 = reg1.MakeOdd(); + int cbit2 = reg2.MakeOdd(); + LehmerGcd(ref reg1, ref reg2); + int cbitMin = Math.Min(cbit1, cbit2); + if (cbitMin > 0) + reg1.ShiftLeft(cbitMin); + } + else + LehmerGcd(ref reg1, ref reg2); + } +*/ + + // This leaves the GCD in reg1 and trash in reg2. + // This uses Lehmer's method, with test due to Jebelean / Belnkiy and Vidunas. + // See Knuth, vol 2, page 345; Jebelean (1993) "Improving the Multiprecision Euclidean Algorithm"; + // and Belenkiy & Vidunas (1998) "A Greatest Common Divisor Algorithm". +/* + private static void LehmerGcd(ref BigIntegerBuilder reg1, ref BigIntegerBuilder reg2) + { + // This value has no real significance. Occ----ionally we want to subtract + // the two registers and keep the absolute value of the difference. To do + // so we need to pass a ref sign to Sub. + int signTmp = +1; + + for (; ; ) + { + reg1.AssertValid(true); + reg2.AssertValid(true); + + int cuMax = reg1._iuLast + 1; + int cuMin = reg2._iuLast + 1; + if (cuMax < cuMin) + { + NumericsHelpers.Swap(ref reg1, ref reg2); + NumericsHelpers.Swap(ref cuMax, ref cuMin); + } + Contract.Assert(cuMax == reg1._iuLast + 1); + Contract.Assert(cuMin == reg2._iuLast + 1); + + if (cuMin == 1) + { + if (cuMax == 1) + reg1._uSmall = NumericsHelpers.GCD(reg1._uSmall, reg2._uSmall); + else if (reg2._uSmall != 0) + reg1.Set(NumericsHelpers.GCD(Mod(ref reg1, reg2._uSmall), reg2._uSmall)); + return; + } + + if (cuMax == 2) + { + reg1.Set(NumericsHelpers.GCD(reg1.GetHigh2(2), reg2.GetHigh2(2))); + return; + } + + if (cuMin <= cuMax - 2) + { + // reg1 is much larger than reg2, so just mod. + reg1.Mod(ref reg2); + continue; + } + + ulong uu1 = reg1.GetHigh2(cuMax); + ulong uu2 = reg2.GetHigh2(cuMax); + Contract.Assert(uu1 != 0 && uu2 != 0); + + int cbit = NumericsHelpers.CbitHighZero(uu1 | uu2); + if (cbit > 0) + { + uu1 = (uu1 << cbit) | (reg1._rgu[cuMax - 3] >> (kcbitUint - cbit)); + // Note that [cuMax - 3] is correct, NOT [cuMin - 3]. + uu2 = (uu2 << cbit) | (reg2._rgu[cuMax - 3] >> (kcbitUint - cbit)); + } + if (uu1 < uu2) + { + NumericsHelpers.Swap(ref uu1, ref uu2); + NumericsHelpers.Swap(ref reg1, ref reg2); + } + + // Make sure we don't overflow. + if (uu1 == ulong.MaxValue || uu2 == ulong.MaxValue) + { + uu1 >>= 1; + uu2 >>= 1; + } + Contract.Assert(uu1 >= uu2); // We ensured this above. + if (uu1 == uu2) + { + // The high bits are the same, so we don't know which + // is larger. No matter, just subtract one from the other + // and keep the absolute value of the result. + Contract.Assert(cuMax == cuMin); + reg1.Sub(ref signTmp, ref reg2); + Contract.Assert(reg1._iuLast < cuMin - 1); + continue; + } + if (NumericsHelpers.GetHi(uu2) == 0) + { + // reg1 is much larger than reg2, so just mod. + reg1.Mod(ref reg2); + continue; + } + + // These are the coefficients to apply to reg1 and reg2 to get + // the new values, using: a * reg1 - b * reg2 and -c * reg1 + d * reg2. + uint a = 1, b = 0; + uint c = 0, d = 1; + + for (; ; ) + { + Contract.Assert(uu1 + a > a); // no overflow + Contract.Assert(uu2 + d > d); + Contract.Assert(uu1 > b); + Contract.Assert(uu2 > c); + Contract.Assert(uu2 + d <= uu1 - b); + + uint uQuo = 1; + ulong uuNew = uu1 - uu2; + while (uuNew >= uu2 && uQuo < 32) + { + uuNew -= uu2; + uQuo++; + } + if (uuNew >= uu2) + { + ulong uuQuo = uu1 / uu2; + if (uuQuo > uint.MaxValue) + break; + uQuo = (uint)uuQuo; + uuNew = uu1 - uQuo * uu2; + } + ulong uuAdNew = a + (ulong)uQuo * c; + ulong uuBcNew = b + (ulong)uQuo * d; + if (uuAdNew > int.MaxValue || uuBcNew > int.MaxValue) + break; + // Jebelean / Belenkiy-Vidunas conditions + if (uuNew < uuBcNew || uuNew + uuAdNew > uu2 - c) + break; + + Contract.Assert(uQuo == (uu1 + a - 1) / (uu2 - c)); + Contract.Assert(uQuo == (uu1 - b) / (uu2 + d)); + + a = (uint)uuAdNew; + b = (uint)uuBcNew; + uu1 = uuNew; + + if (uu1 <= b) + { + Contract.Assert(uu1 == b); + break; + } + + Contract.Assert(uu1 + a > a); // no overflow + Contract.Assert(uu2 + d > d); + Contract.Assert(uu2 > c); + Contract.Assert(uu1 > b); + Contract.Assert(uu1 + a <= uu2 - c); + + uQuo = 1; + uuNew = uu2 - uu1; + while (uuNew >= uu1 && uQuo < 32) + { + uuNew -= uu1; + uQuo++; + } + if (uuNew >= uu1) + { + ulong uuQuo = uu2 / uu1; + if (uuQuo > uint.MaxValue) + break; + uQuo = (uint)uuQuo; + uuNew = uu2 - uQuo * uu1; + } + uuAdNew = d + (ulong)uQuo * b; + uuBcNew = c + (ulong)uQuo * a; + if (uuAdNew > int.MaxValue || uuBcNew > int.MaxValue) + break; + // Jebelean / Belenkiy-Vidunas conditions + if (uuNew < uuBcNew || uuNew + uuAdNew > uu1 - b) + break; + + Contract.Assert(uQuo == (uu2 + d - 1) / (uu1 - b)); + Contract.Assert(uQuo == (uu2 - c) / (uu1 + a)); + + d = (uint)uuAdNew; + c = (uint)uuBcNew; + uu2 = uuNew; + + if (uu2 <= c) + { + Contract.Assert(uu2 == c); + break; + } + } + + if (b == 0) + { + Contract.Assert(a == 1 && c == 0 && d == 1); + Contract.Assert(uu1 > uu2); // We ensured this above. + if (uu1 / 2 >= uu2) + reg1.Mod(ref reg2); + else + reg1.Sub(ref signTmp, ref reg2); + } + else + { + // Replace reg1 with a * reg1 - b * reg2. + // Replace reg2 with -c * reg1 + d * reg2. + // Do everything mod cuMin uint's. + reg1.SetSizeKeep(cuMin, 0); + reg2.SetSizeKeep(cuMin, 0); + int nCarry1 = 0; + int nCarry2 = 0; + for (int iu = 0; iu < cuMin; iu++) + { + uint u1 = reg1._rgu[iu]; + uint u2 = reg2._rgu[iu]; + long nn1 = (long)u1 * a - (long)u2 * b + nCarry1; + long nn2 = (long)u2 * d - (long)u1 * c + nCarry2; + nCarry1 = (int)(nn1 >> kcbitUint); + nCarry2 = (int)(nn2 >> kcbitUint); + reg1._rgu[iu] = (uint)nn1; + reg2._rgu[iu] = (uint)nn2; + } + reg1.Trim(); + reg2.Trim(); + } + } + } +*/ + + /*internal int CbitLowZero() + { + AssertValid(true); + if (_iuLast == 0) + { + if ((_uSmall & 1) != 0 || _uSmall == 0) + return 0; + return NumericsHelpers.CbitLowZero(_uSmall); + } + + int iuMin = 0; + while (_rgu[iuMin] == 0) + iuMin++; + int cbit = NumericsHelpers.CbitLowZero(_rgu[iuMin]); + return cbit + iuMin * kcbitUint; + }*/ + + // Shift right until the number is odd. Return the number of bits + // shifted. Asserts that the register is trimmed. +/* + internal int MakeOdd() + { + AssertValid(true); + int cbit = CbitLowZero(); + if (cbit > 0) + ShiftRight(cbit); + return cbit; + } +*/ + } +} diff --git a/runtime/VMProtect.Runtime/Numerics/NumericHelpers.cs b/runtime/VMProtect.Runtime/Numerics/NumericHelpers.cs new file mode 100644 index 0000000..68c61bc --- /dev/null +++ b/runtime/VMProtect.Runtime/Numerics/NumericHelpers.cs @@ -0,0 +1,425 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== + +using System; + +using Contracts = System.Diagnostics.Debug; +using Contract = System.Diagnostics.Debug; +//using System.Runtime.InteropServices; + +// ReSharper disable once CheckNamespace +namespace Numerics +{ + +/* + [StructLayout(LayoutKind.Explicit)] + internal struct DoubleUlong + { + [FieldOffset(0)] + internal double dbl; + [FieldOffset(0)] + internal ulong uu; + } +*/ + + + internal static class NumericsHelpers + { + private const int KcbitUint = 32; + + /*internal static void GetDoubleParts(double dbl, out int sign, out int exp, out ulong man, out bool fFinite) + { + //Contract.Ensures(Contract.ValueAtReturn(out sign) == +1 || Contract.ValueAtReturn(out sign) == -1); + + DoubleUlong du; + du.uu = 0; + du.dbl = dbl; + + sign = 1 - ((int)(du.uu >> 62) & 2); + man = du.uu & 0x000FFFFFFFFFFFFF; + exp = (int)(du.uu >> 52) & 0x7FF; + if (exp == 0) + { + // Denormalized number. + fFinite = true; + if (man != 0) + exp = -1074; + } + else if (exp == 0x7FF) + { + // NaN or Inifite. + fFinite = false; + exp = int.MaxValue; + } + else + { + fFinite = true; + man |= 0x0010000000000000; + exp -= 1075; + } + } + + internal static double GetDoubleFromParts(int sign, int exp, ulong man) + { + DoubleUlong du; + du.dbl = 0; + + if (man == 0) + du.uu = 0; + else + { + // Normalize so that 0x0010 0000 0000 0000 is the highest bit set. + int cbitShift = CbitHighZero(man) - 11; + if (cbitShift < 0) + man >>= -cbitShift; + else + man <<= cbitShift; + exp -= cbitShift; + Contract.Assert((man & 0xFFF0000000000000) == 0x0010000000000000); + + // Move the point to just behind the leading 1: 0x001.0 0000 0000 0000 + // (52 bits) and skew the exponent (by 0x3FF == 1023). + exp += 1075; + + if (exp >= 0x7FF) + { + // Infinity. + du.uu = 0x7FF0000000000000; + } + else if (exp <= 0) + { + // Denormalized. + exp--; + if (exp < -52) + { + // Underflow to zero. + du.uu = 0; + } + else + { + du.uu = man >> -exp; + Contract.Assert(du.uu != 0); + } + } + else + { + // Mask off the implicit high bit. + du.uu = (man & 0x000FFFFFFFFFFFFF) | ((ulong)exp << 52); + } + } + + if (sign < 0) + du.uu |= 0x8000000000000000; + + return du.dbl; + } + */ + + + // Do an in-place twos complement of d and also return the result. + // "Dangerous" because it causes a mutation and needs to be used + // with care for immutable types + internal static void DangerousMakeTwosComplement(uint[] d) + { + // first do complement and +1 as long as carry is needed + int i = 0; + uint v = 0; + for (; i < d.Length; i++) + { + v = ~d[i] + 1; + d[i] = v; + if (v != 0) { i++; break; } + } + if (v != 0) + { + // now ones complement is sufficient + for (; i < d.Length; i++) + { + d[i] = ~d[i]; + } + } + else + { + //??? this is weird + d = resize(d, d.Length + 1); + d[d.Length - 1] = 1; + } + } + + // ReSharper disable once InconsistentNaming + private static uint[] resize(uint[] v, int len) + { + if (v.Length == len) return v; + uint[] ret = new uint[len]; + int n = Math.Min(v.Length, len); + for (int i = 0; i < n; i++) + { + ret[i] = v[i]; + } + return ret; + } + + internal static void Swap<T>(ref T a, ref T b) + { + T tmp = a; + a = b; + b = tmp; + } + + // ReSharper disable once InconsistentNaming +/* + internal static uint GCD(uint u1, uint u2) + { + const int cvMax = 32; + if (u1 < u2) + goto LOther; + LTop: + Contract.Assert(u2 <= u1); + if (u2 == 0) + return u1; + for (int cv = cvMax; ; ) + { + u1 -= u2; + if (u1 < u2) + break; + if (--cv == 0) + { + u1 %= u2; + break; + } + } + LOther: + Contract.Assert(u1 < u2); + if (u1 == 0) + return u2; + for (int cv = cvMax; ; ) + { + u2 -= u1; + if (u2 < u1) + break; + if (--cv == 0) + { + u2 %= u1; + break; + } + } + goto LTop; + } +*/ + + // ReSharper disable once InconsistentNaming +/* + internal static ulong GCD(ulong uu1, ulong uu2) + { + const int cvMax = 32; + if (uu1 < uu2) + goto LOther; + LTop: + Contract.Assert(uu2 <= uu1); + if (uu1 <= uint.MaxValue) + goto LSmall; + if (uu2 == 0) + return uu1; + for (int cv = cvMax; ; ) + { + uu1 -= uu2; + if (uu1 < uu2) + break; + if (--cv == 0) + { + uu1 %= uu2; + break; + } + } + LOther: + Contract.Assert(uu1 < uu2); + if (uu2 <= uint.MaxValue) + goto LSmall; + if (uu1 == 0) + return uu2; + for (int cv = cvMax; ; ) + { + uu2 -= uu1; + if (uu2 < uu1) + break; + if (--cv == 0) + { + uu2 %= uu1; + break; + } + } + goto LTop; + + LSmall: + uint u1 = (uint)uu1; + uint u2 = (uint)uu2; + if (u1 < u2) + goto LOtherSmall; + LTopSmall: + Contract.Assert(u2 <= u1); + if (u2 == 0) + return u1; + for (int cv = cvMax; ; ) + { + u1 -= u2; + if (u1 < u2) + break; + if (--cv == 0) + { + u1 %= u2; + break; + } + } + LOtherSmall: + Contract.Assert(u1 < u2); + if (u1 == 0) + return u2; + for (int cv = cvMax; ; ) + { + u2 -= u1; + if (u2 < u1) + break; + if (--cv == 0) + { + u2 %= u1; + break; + } + } + goto LTopSmall; + } +*/ + + internal static ulong MakeUlong(uint uHi, uint uLo) + { + return ((ulong)uHi << KcbitUint) | uLo; + } + + internal static uint GetLo(ulong uu) + { + return (uint)uu; + } + + internal static uint GetHi(ulong uu) + { + return (uint)(uu >> KcbitUint); + } + +/* + internal static uint Abs(int a) + { + uint mask = (uint)(a >> 31); + return ((uint)a ^ mask) - mask; + } +*/ + + // internal static ulong Abs(long a) { + // ulong mask = (ulong)(a >> 63); + // return ((ulong)a ^ mask) - mask; + // } + + private static uint CombineHash(uint u1, uint u2) + { + return ((u1 << 7) | (u1 >> 25)) ^ u2; + } + + internal static int CombineHash(int n1, int n2) + { + return (int)CombineHash((uint)n1, (uint)n2); + } + internal static int CbitHighZero(uint u) + { + if (u == 0) + return 32; + + int cbit = 0; + if ((u & 0xFFFF0000) == 0) + { + cbit += 16; + u <<= 16; + } + if ((u & 0xFF000000) == 0) + { + cbit += 8; + u <<= 8; + } + if ((u & 0xF0000000) == 0) + { + cbit += 4; + u <<= 4; + } + if ((u & 0xC0000000) == 0) + { + cbit += 2; + u <<= 2; + } + if ((u & 0x80000000) == 0) + cbit += 1; + return cbit; + } + + /*internal static int CbitLowZero(uint u) + { + if (u == 0) + return 32; + + int cbit = 0; + if ((u & 0x0000FFFF) == 0) + { + cbit += 16; + u >>= 16; + } + if ((u & 0x000000FF) == 0) + { + cbit += 8; + u >>= 8; + } + if ((u & 0x0000000F) == 0) + { + cbit += 4; + u >>= 4; + } + if ((u & 0x00000003) == 0) + { + cbit += 2; + u >>= 2; + } + if ((u & 0x00000001) == 0) + cbit += 1; + return cbit; + } + + internal static int CbitHighZero(ulong uu) + { + if ((uu & 0xFFFFFFFF00000000) == 0) + return 32 + CbitHighZero((uint)uu); + return CbitHighZero((uint)(uu >> 32)); + }*/ + + // internal static int CbitLowZero(ulong uu) { + // if ((uint)uu == 0) + // return 32 + CbitLowZero((uint)(uu >> 32)); + // return CbitLowZero((uint)uu); + // } + // + // internal static int Cbit(uint u) { + // u = (u & 0x55555555) + ((u >> 1) & 0x55555555); + // u = (u & 0x33333333) + ((u >> 2) & 0x33333333); + // u = (u & 0x0F0F0F0F) + ((u >> 4) & 0x0F0F0F0F); + // u = (u & 0x00FF00FF) + ((u >> 8) & 0x00FF00FF); + // return (int)((ushort)u + (ushort)(u >> 16)); + // } + // + // static int Cbit(ulong uu) { + // uu = (uu & 0x5555555555555555) + ((uu >> 1) & 0x5555555555555555); + // uu = (uu & 0x3333333333333333) + ((uu >> 2) & 0x3333333333333333); + // uu = (uu & 0x0F0F0F0F0F0F0F0F) + ((uu >> 4) & 0x0F0F0F0F0F0F0F0F); + // uu = (uu & 0x00FF00FF00FF00FF) + ((uu >> 8) & 0x00FF00FF00FF00FF); + // uu = (uu & 0x0000FFFF0000FFFF) + ((uu >> 16) & 0x0000FFFF0000FFFF); + // return (int)((uint)uu + (uint)(uu >> 32)); + // } + } +} + diff --git a/runtime/VMProtect.Runtime/Properties/AssemblyInfo.cs b/runtime/VMProtect.Runtime/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..4174fea --- /dev/null +++ b/runtime/VMProtect.Runtime/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("VMProtect.Runtime")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("VMProtect.Runtime")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("544f194e-b3a9-40a8-8f75-bd12b10868bf")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/runtime/VMProtect.Runtime/StringManager.cs b/runtime/VMProtect.Runtime/StringManager.cs new file mode 100644 index 0000000..33230fa --- /dev/null +++ b/runtime/VMProtect.Runtime/StringManager.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; + +// ReSharper disable once CheckNamespace +namespace VMProtect +{ + public class StringManager + { + public StringManager(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); + _entries = new Dictionary<uint, uint>(); + _key = BitConverter.ToUInt32(key, 0); + + var startPosition = (uint)Faces.STRING_INFO; + // DecryptDirectory + var directory = new byte[8]; + Marshal.Copy(new IntPtr(_instance + startPosition), directory, 0, directory.Length); + directory = _cipher.Decrypt(directory); + var numberOfEntries = BitConverter.ToUInt32(directory, 0); + + var entry = new byte[16]; + for (uint i = 0; i < numberOfEntries; i++) + { + // DecryptEntry + uint pos = startPosition + 8 + i * 16; + Marshal.Copy(new IntPtr(_instance + pos), entry, 0, 16); + entry = _cipher.Decrypt(entry); + _entries.Add(BitConverter.ToUInt32(entry, 0), pos); + } + } + + public string DecryptString(uint stringId) + { + uint pos; + if (_entries.TryGetValue(stringId, out pos)) + { + var entry = new byte[16]; + Marshal.Copy(new IntPtr(_instance + pos), entry, 0, 16); + entry = _cipher.Decrypt(entry); + + var size = BitConverter.ToInt32(entry, 8); + var stringData = new byte[size]; + Marshal.Copy(new IntPtr(_instance + BitConverter.ToUInt32(entry, 4)), stringData, 0, size); + for (var c = 0; c < size; c++) + { + stringData[c] = (byte)(stringData[c] ^ BitRotate.Left(_key, c) + c); + } + return Encoding.Unicode.GetString(stringData); + } + + return null; + } + + private readonly long _instance; + private readonly CipherRC5 _cipher; + private readonly Dictionary<uint, uint> _entries; + private readonly uint _key; + } +}
\ No newline at end of file diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/LicensingManagerTests.cs b/runtime/VMProtect.Runtime/Tests/UnitTestProject/LicensingManagerTests.cs new file mode 100644 index 0000000..015a0a1 --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/LicensingManagerTests.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.Security.Cryptography; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using VMProtect; + +namespace UnitTestProject +{ + [TestClass] + public class LicensingManagerTests + { + private class Data + { + public void PushByte(byte b) { _data.Add(b); } + //void PushDWord(int d) { PushBuff(BitConverter.GetBytes(d)); } + /*void PushQWord(ulong q) { PushBuff(&q, sizeof(q)); } + void PushWord(ushort w) { PushBuff(&w, sizeof(w)); }*/ + public void PushBuff(byte[] buff) + { + _data.AddRange(buff); + } + /*public void InsertByte(int position, byte value) + { + _data.Insert(position, value); + }*/ + + /*uint32_t ReadDWord(size_t nPosition) const + { + return *reinterpret_cast<const uint32_t *>(&m_vData[nPosition]); + }*/ + + public void WriteDWord(int position, int value) + { + foreach (var b in BitConverter.GetBytes(value)) + { + _data[position++] = b; + } + } + + public int Size => _data.Count; + //public void clear() { _data.Clear(); } + //public bool empty() { return _data.Count == 0; } + //void resize(int size) { _data.resize(size); } + //void resize(int size, uint8_t value) { m_vData.resize(size, value); } + public byte[] ToArray() { return _data.ToArray(); } + + private readonly List<byte> _data; + + public Data(int sz) + { + _data = new List<byte>(new byte[sz]); + } + } + + [TestMethod] + public void ParseSerial() + { + //var key = new byte[] {1, 2, 3, 4, 5, 6, 7, 8}; + var data = new Data(sizeof(uint) * (int)LicensingManager.Fields.Count); + + var publicExp = Convert.FromBase64String("AAEAAQ=="); + var modulus = Convert.FromBase64String("pwUqwaM8IOukyx06Lvi5YNQ70JE7pwg7K+pmM/vCe1CUseHKFM1v1m11geDjVsAt38AnaiFs3JhtTs80ySCIxOSyvMw6Cd52k6N6dn7LAx1mxQLJLhYeMMJYbplMHnMLwYN0+IO58OVbEqRyaJV2ExolnK2EYZL7QRXujGY7/sOoOMF3p6GsWJK6kkBJICIoL9hHWBQMO6/9rmls/+EhaWuP80Vx0+H2OlrQ58K+TJeyE393cvb4QufiEPpCNaB50Klee9QUnsjSW/bTnmGn4Bi5+cowRbawUY73Q5I58fMAXiH9ueDPuNMR9YKDgW9GxunLmYkbuwqIp/v7kw3cfMBM0ihhB0B8UhjyAMAGLzJWX3H/H6Zrz41g9PbPjTAxfsTaCrxoqjaTaO4zk9YsI//VX9Fhivcy913SevBpNandziGfYH/oHW2xDy9AfwkE1wuIBlLj7c/k8U1YmmRAmkoCzlmB7EU4ClNltboh1uARUQ6wW30upppnuYhGkTy7"); + var black = Convert.FromBase64String("A7zybXsboP8UVQ4x8mCSPVlm4W8G2gMbKOiLDFIX28dpdl6AzdqGCxIeiXRfaPBgeGeyL1BB+3pLVJ9SGkjc/BXy1hYkjJCwacADVEWoR14blpa3hdx+R/WHe8uhS9ShV1hxviIKRt4UJbIjyqH7tMu2p8KuVbB0IwM0dFPnVujgNmNN2/BeOQl/RFMmD+TpLzFHetvt0Dx7rk8MKINv3SoyL97QWNvwCbL35JIZN5DtMdZ3MfO/fxz/1kSTNbccciqEljRiC74zMsNz2LNkf1hwxES96yGBsd2oOTe+DJx43j8iZ7UD75iwIGKoPxysOYnHTewT2ofK9d6SMl4rIyxt6TI+KzXppRyhVieHtEIo9/NIm7ABnkLTJvy4tjFftPocJP3E5v9ra8YBQ2y3PKz04BkesCeKiVPyBqy9phxHtjKpIimlm73GSfDMVZ+xgLsn/Ui6XSW8kB8ai+rEA1KFosfmsVPASiuXJAHJaNfY4ULKZWOfGcoPDh1KjhmFq7INiQaMy+rml/EiKv4p9k3vomv41ll5IoIVkxZaMY8Gtkl5UYWWJUMlJgphM9+LOkWCLX1fm7ZUiJbfHkmVTTFZ6SxhxoeO73yovFdt37I/17tbM0jjQjC1Q172ZPQmWPBP2NaPTXglJdkSKWYWw8pG6EJh+eRrfZ1USmdkU2TI0FUDSwJ2F2RSkObaDx4WFrBz0xddLmEl0XEJaQI/TTRZk5hQB/20NPzavgiAQ39p62LR7hZTqnR4zshiFv2sChe4x2p4XzBx4NKx1Zw6QaZrfwX47R3dc2K80jHIisj9Ltnr3qUgr5S0Nbp6+8BKB6RFcPuPAi24SVh7e5KgvoKNB/FzJqZnE9FCiryEeRbRwU26g3l+orZTM/jm1niFKlgrvdRweVqVza4JBnbeTGF2t8PstMH6Vx4+gpoJWyoQY6acm5MSFyl2DLXCcd6MmoRyp30Ge209zoOjj7c5PGRYxjiiUO04gaGhh7YyUp7VTHmd2llSQaKhsyw/7k3OqEKTinSRmdiDNsmfp8fOqtd388jGyhME6zzda8u1Ex6uvHkrk2arjVSeQk3XED4ZPqyRbLDZYGZcp9HheDdciX56rK39NTXetOWN8p4KW6aMa91EUTaCiafQVhO6dYzO+1ybRjOR7ND7nOnt9zUEerzNbIkCFT6uGTqtue0FZe4Zxunlv9D1mA4266xWfZfIPSzXD2cVAerBjr2BtYHOolDP1dRu1JcPwXGxOMiDL76x1NghovHsQxlwcfWT9CO+ywvhEkiwirt0UsTbACSslWD2sNLTdQ1aLNkqM9FjJzN7uKHk/J4OZtmNFRsxxZUvWYKYb/+q93FEsbMr5YfSPLlezvf6fL3k6tSKB5sFuk/rsgeBQYOwUGIKDRc8c0yNd8kEXOxvmzCGEv2/95Lh7XxXEUaHYKki7TR73v+H6pIiYmTOHg/Z9F4OjzHxb6HIUq6bzNywpzguJjBKqhnoRfJMwBr9P3NQ+CU5VaBXwxTlMWtW9Ihou7a+Hio34w2YGYdtr8BzMjT03VrAOtLH4V0HZj/UTAkTFaGDK/bdOAYXH/fz9GVBVU94hB86ii4e9ulYanZkiRJMDwTlNTup5jRVAR7/nM4H0Q0evDGRo7k4IP5CtLb6fg=="); + + data.WriteDWord((int)LicensingManager.Fields.PublicExpOffset * sizeof(uint), data.Size); + data.WriteDWord((int)LicensingManager.Fields.PublicExpSize * sizeof(uint), publicExp.Length); + data.PushBuff(publicExp); + + data.WriteDWord((int)LicensingManager.Fields.ModulusOffset * sizeof(uint), data.Size); + data.WriteDWord((int)LicensingManager.Fields.ModulusSize * sizeof(uint), modulus.Length); + data.PushBuff(modulus); + + data.WriteDWord((int)LicensingManager.Fields.BlacklistOffset * sizeof(uint), data.Size); + data.WriteDWord((int)LicensingManager.Fields.BlacklistSize * sizeof(uint), black.Length); + data.PushBuff(black); + + var crcPos = data.Size; + data.WriteDWord((int)LicensingManager.Fields.CRCOffset * sizeof(uint), crcPos); + var size = crcPos + 16; + + using (var hash = new SHA1Managed()) + { + var p = hash.ComputeHash(data.ToArray()); + for (var i = crcPos; i < size; i++) + { + data.PushByte(p[i - crcPos]); + } + } + + var licensingManager = new LicensingManager(data.ToArray()); + Assert.AreEqual(SerialState.Blacklisted, licensingManager.SetSerialNumber("H2GfYz579KQ5poUTxKRWsUd7o+1XSwaJrK7CmwG15rNuo3Wa+vy660rJkRaWTrELbyyIe2k15973P13WJvxDR8myQCMi8Pv9D9k9iblCTAZL9vOcX55g2Vk4i+x+DEDn601kjvkL7RvHug1SYq6GqKm4dnApwlGvbnSebSDwrhh0E5g9I/XA5pa7hQUQwcBoXq6A7e7Blj8FbJ1JBdYUJY7RavgFE9KYfTXn5ceCwPr0gR3A++W66amQdxWnFxyyOFwfCPuZDk+LCgqqAgMyj5PRPcLA3nanXLDLPGva1wa1EEP0qvx6yCSpDURP94GxQGY1xjPlZagbuLaYyWn7bb/sLsYNXVHE1a+YNFORn890tbZ1D6i+wTEa254oF3yKa5GYTQmRWJQR+OXqaTK/wNG4y8dAUisOmQpevrSrD7pQj7ZLGOChmw+KWB6SozSHtIMY665ji9tMP8mq8OUSVSZ9N9q3Zh/xnW0W8sGck5IzTr3JtT0a3iOXSYfijpmy")); + Assert.AreEqual(SerialState.Blacklisted, licensingManager.GetSerialNumberState()); + var snd = new SerialNumberData(); + Assert.IsTrue(licensingManager.GetSerialNumberData(snd)); + Assert.AreEqual("", snd.EMail); //a20071234@163.com + Assert.AreEqual("", snd.UserName); //Su Ying + Assert.AreEqual(DateTime.MaxValue, snd.Expires); + Assert.AreEqual(DateTime.MaxValue, snd.MaxBuild); + Assert.AreEqual(0, snd.RunningTime); + Assert.AreEqual(SerialState.Blacklisted, snd.State); + Assert.AreEqual(0, snd.UserData.Length); + + Assert.AreEqual(SerialState.Success, licensingManager.SetSerialNumber("V5z/4JRVkIhN/D7KkHUBfM2ww3VMxq4r7SgRViTG840294nBiqLer9QUyuX/oyS5sxwzgtMruYYK2n8PvrilVRhFj3rgoK67V + 0 / kJxNmypnWY + PbNurXbimp8KfTF6aOydLQyo26M2iRJhnPCXXInXB4QMi5dPNf41cdVelwt + C5hSfV7zPeJZRLbWv + AMScBJEmy1AW3AWUokfHUMSonq75LxBc3jLnDESz8UGTNWrIXSEiRjrueszSM7uGEmWemUjS + MzgL + F + DfsKNTc2KTEctprxQmxcJZsN4rZS0q8UJo3eA0HXgrrFlxYkLqgcq + 8 / 018W3l79nR17ZDQsUuJFfrElY8F6OGtbis2j9YyCszcWoKQLB3bSgWrKXPAlrEN4VuxMk0wbq + sYZLIt / npAmFheE7wHhnN1PubK84BpQFZKnkrIrsC43PJ2ss2WOQl / vqTxhTbbDyPEE69NW8R + fUanth5sglfableZjt4WH + hwgiGL + D8wHQlWgT7")); + Assert.AreEqual(SerialState.Success, licensingManager.GetSerialNumberState()); + Assert.IsTrue(licensingManager.GetSerialNumberData(snd)); + Assert.AreEqual("jleber@onvisionnetworks.com", snd.EMail); + Assert.AreEqual("Onvision Networks Limited", snd.UserName); + Assert.AreEqual(DateTime.MaxValue, snd.Expires); + Assert.AreEqual(new DateTime(2017, 4, 11), snd.MaxBuild); + Assert.AreEqual(0, snd.RunningTime); + Assert.AreEqual(SerialState.Success, snd.State); + Assert.AreEqual(1, snd.UserData.Length); + CollectionAssert.AreEqual(snd.UserData, new byte[] {4}); + } + + /*[TestMethod] + public void ParseSerialTimeLimitedHWID() + { + //TODO + }*/ + } +}
\ No newline at end of file diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/LoaderTests.cs b/runtime/VMProtect.Runtime/Tests/UnitTestProject/LoaderTests.cs new file mode 100644 index 0000000..5ad8afa --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/LoaderTests.cs @@ -0,0 +1,47 @@ +using System.Runtime.InteropServices; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using VMProtect; + +namespace UnitTestProject +{ + [TestClass] + public class LoaderTests + { + [TestMethod] + public void LzmaDecode() + { + byte[] properties = + { + 0x5d, 0, 0, 0, 1 // 5 bytes props + }; + byte[] src = + { + 0x00, 0x4e, 0x3a, 0x46, 0xeb, 0xe0, 0x06, 0x71, 0xc9, 0xe1, + 0xe6, 0x37, 0xfd, 0x9b, 0xb6, 0xd0, 0x76, 0x3f, 0xc8, 0x73, + 0xee, 0x11, 0xb6, 0x41, 0xaa, 0xb1, 0x7b, 0x7b, 0xef, 0xc6, + 0x9f, 0xff, 0xf6, 0x1d, 0x28, 0x00 //36 bytes packed + }; + byte [] dstExpected = { 0x9c, 0xe9, 0x57, 0xbe, 0x00, 0x00, 0xc3, 0xe9, 0x24, 0x2c, 0x01, 0x00, 0xe9, 0xef, 0x65, 0x00, 0x00, 0xe9, 0xc0, 0x41, 0x06, 0x00, 0xc3, 0x56, 0x57 }; + var pinnedSrc = GCHandle.Alloc(src, GCHandleType.Pinned); + uint dstSize = 65536; + var dstPtr = Marshal.AllocHGlobal((int)dstSize); + try + { + dstSize = int.MaxValue; + uint srcSize /*= (uint)src.Length*/; + var res = Loader.LzmaDecode(dstPtr, pinnedSrc.AddrOfPinnedObject(), properties, ref dstSize, out srcSize); + Assert.AreEqual(true, res); + Assert.AreEqual(dstExpected.Length, (int)dstSize); + var dst = new byte[dstSize]; + Marshal.Copy(dstPtr, dst, 0, (int)dstSize); + CollectionAssert.AreEqual(dstExpected, dst); + Assert.AreEqual(src.Length, (int)srcSize); + } + finally + { + pinnedSrc.Free(); + Marshal.FreeHGlobal(dstPtr); + } + } + } +} diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/MsilToVmTestCompiler.cs b/runtime/VMProtect.Runtime/Tests/UnitTestProject/MsilToVmTestCompiler.cs new file mode 100644 index 0000000..1e205c5 --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/MsilToVmTestCompiler.cs @@ -0,0 +1,100 @@ +using System; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.ExceptionServices; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace UnitTestProject +{ + public abstract class MsilToVmTestCompiler + { + public enum LongEnum : long { Eval1 = 1, Evalm1 = -1 } + public enum ULongEnum : ulong { Evalm1 = 0xFFFFFFFFFFFFFFFF } + public enum ByteEnum : byte {} + public enum SByteEnum : sbyte { } + public enum IntEnum /*: int*/ { } + public enum UIntEnum : uint { } + public enum ShortEnum : short { } + public enum UShortEnum : ushort { } + + public static byte[] GetIlBytes(DynamicMethod dynamicMethod) + { + // ReSharper disable once PossibleNullReferenceException + var resolver = typeof(DynamicMethod).GetField("m_resolver", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(dynamicMethod); + if (resolver == null) throw new ArgumentException("The dynamic method's IL has not been finalized."); + // ReSharper disable once PossibleNullReferenceException + return (byte[])resolver.GetType().GetField("m_code", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(resolver); + } + + public abstract Stream CreateVmStream(Type rt, ParameterInfo[] pi, Type[] locals, byte[] ilBytes); + + public enum InvokeTestCombineError + { + NoError, + NoErrorByStdEx, // текущий стандарт ECMA-335 оставляет некоторые сценарии как "неопределенное поведение", но их можно определить + VmOtherExceptionExpected, + VmOtherTypeExpected, + VmOtherValueExpected, + Cnt + }; + // dyn/vm обязаны что-то возвратить, либо выбросить исключение + // (в тестах не должно быть методов, возвращающих void, null или исключение в качестве retVal) + [HandleProcessCorruptedStateExceptions] + public InvokeTestCombineError InvokeTestCombine(DynamicMethod dyn, object[] parameters, out object dynRet, out object vmRet, out string err) + { + Type exceptionType = null; + err = ""; + try + { + dynRet = dyn.Invoke(null, parameters); + Assert.IsNotNull(dynRet); + Assert.IsInstanceOfType(dynRet, dyn.ReturnType); + } + catch (Exception e) + { + Assert.IsInstanceOfType(e, typeof(TargetInvocationException)); + Assert.IsNotNull(e.InnerException); + exceptionType = e.InnerException.GetType(); + dynRet = e.InnerException; + } + var vmStream = CreateVmStream(dyn.ReturnType, dyn.GetBaseDefinition().GetParameters(), + //FIXME dyn.GetMethodBody().LocalVariables.Select(o => o.LocalType).ToArray(), + new Type[] {}, + GetIlBytes(dyn)); + try + { + vmRet = Invoke(parameters, vmStream); + if(exceptionType != null) + { + err = $"VmOtherExceptionExpected: {exceptionType.FullName}, actual: {vmRet}"; + return InvokeTestCombineError.VmOtherExceptionExpected; + } + if (vmRet == null || vmRet.GetType() != dyn.ReturnType) + { + err = $"VmOtherTypeExpected: {dyn.ReturnType.FullName}, actual: {((vmRet != null) ? vmRet.GetType().FullName : "null")}"; + return InvokeTestCombineError.VmOtherTypeExpected; + } + } + catch (Exception e) + { + vmRet = e; + if (e.GetType() != exceptionType) + { + err = $"VmOtherExceptionExpected: {((exceptionType != null) ? exceptionType.FullName : dynRet)}, actual: {e.GetType().FullName}"; + return InvokeTestCombineError.VmOtherExceptionExpected; + } + return InvokeTestCombineError.NoError; + } + if (dynRet.Equals(vmRet)) + { + return InvokeTestCombineError.NoError; + } + err = $"VmOtherValueExpected: {dynRet}, actual: {vmRet}"; + return InvokeTestCombineError.VmOtherValueExpected; + } + + public abstract object Invoke(object[] parameters, Stream vmStream); + } +} diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/Properties/AssemblyInfo.cs b/runtime/VMProtect.Runtime/Tests/UnitTestProject/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..cb78989 --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("UnitTestProject")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("UnitTestProject")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("aefca063-245a-4d50-a5a3-82188ce677fa")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/ElementedTypeHelper.cs b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/ElementedTypeHelper.cs new file mode 100644 index 0000000..b1dc170 --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/ElementedTypeHelper.cs @@ -0,0 +1,172 @@ +using System; +using System.Diagnostics; + +namespace UnitTestProject.RefVm +{ + // Token: 0x02000048 RID: 72 + internal static class ElementedTypeHelper // \u0008\u2005 + { + // Token: 0x06000307 RID: 775 RVA: 0x000148D8 File Offset: 0x00012AD8 + public static Type TryGoToElementType(Type t) // \u0002 + { + if (t.IsByRef || t.IsArray || t.IsPointer) + { + return TryGoToElementType(t.GetElementType()); + } + return t; + } + + // Token: 0x06000308 RID: 776 RVA: 0x00014900 File Offset: 0x00012B00 + public static Type TryGoToPointerOrReferenceElementType(Type t) // \u0003 + { + if (t.HasElementType && !t.IsArray) + { + t = t.GetElementType(); + } + return t; + } + + // Token: 0x06000309 RID: 777 RVA: 0x00014920 File Offset: 0x00012B20 + public static MyCollection<ElementedTypeDescrItem> NestedElementTypes(Type type) // \u0002 + { + var collection = new MyCollection<ElementedTypeDescrItem>(); + while (true) + { + Debug.Assert(type != null, "type != null"); + if(type == null) return collection; + if (type.IsArray) + { + collection.PushBack(new ElementedTypeDescrItem + { + K = ElementedTypeDescrItem.Kind.Array1, + ArrayRank = type.GetArrayRank() + }); + } + else if (type.IsByRef) + { + collection.PushBack(new ElementedTypeDescrItem + { + K = ElementedTypeDescrItem.Kind.ByRef2 + }); + } + else + { + if (!type.IsPointer) + { + break; + } + collection.PushBack(new ElementedTypeDescrItem + { + K = ElementedTypeDescrItem.Kind.Ponter0 + }); + } + type = type.GetElementType(); + } + return collection; + } + + // Token: 0x0600030A RID: 778 RVA: 0x000149B0 File Offset: 0x00012BB0 + public static MyCollection<ElementedTypeDescrItem> NestedElementTypes(string text) // \u0002 + { + var collection = new MyCollection<ElementedTypeDescrItem>(); + while (true) + { + if (text.EndsWith(StringDecryptor.GetString(-1550346966) /* & */, StringComparison.Ordinal)) + { + collection.PushBack(new ElementedTypeDescrItem + { + K = ElementedTypeDescrItem.Kind.ByRef2 + }); + text = text.Substring(0, text.Length - 1); + } + else if (text.EndsWith(StringDecryptor.GetString(-1550346958) /* * */, StringComparison.Ordinal)) + { + collection.PushBack(new ElementedTypeDescrItem + { + K = ElementedTypeDescrItem.Kind.Ponter0 + }); + text = text.Substring(0, text.Length - 1); + } + else if (text.EndsWith(StringDecryptor.GetString(-1550346950) /* [] */, StringComparison.Ordinal)) + { + collection.PushBack(new ElementedTypeDescrItem + { + K = ElementedTypeDescrItem.Kind.Array1, + ArrayRank = 1 + }); + text = text.Substring(0, text.Length - 2); + } + else + { + if (!text.EndsWith(StringDecryptor.GetString(-1550346811) /* ,] */, StringComparison.Ordinal)) + { + return collection; + } + var rank = 1; + var remainLen = -1; + for (var i = text.Length - 2; i >= 0; i--) + { + var c = text[i]; + if (c != ',') + { + if (c != '[') + { + throw new InvalidOperationException(StringDecryptor.GetString(-1550346804) /* VM-3012 */); + } + remainLen = i; + i = -1; + } + else + { + rank++; + } + } + if (remainLen < 0) + { + throw new InvalidOperationException(StringDecryptor.GetString(-1550346790) /* VM-3014 */); + } + text = text.Substring(0, remainLen); + collection.PushBack(new ElementedTypeDescrItem + { + K = ElementedTypeDescrItem.Kind.Array1, + ArrayRank = rank + }); + } + } + } + + // Token: 0x0600030B RID: 779 RVA: 0x00014B30 File Offset: 0x00012D30 + public static Type PopType(Type type, MyCollection<ElementedTypeDescrItem> descr) // \u0002 + { + while (descr.Count > 0) + { + var p = descr.PopBack(); + switch (p.K) + { + case ElementedTypeDescrItem.Kind.Ponter0: + type = type.MakePointerType(); + break; + case ElementedTypeDescrItem.Kind.Array1: + type = (p.ArrayRank == 1) ? type.MakeArrayType() : type.MakeArrayType(p.ArrayRank); + break; + case ElementedTypeDescrItem.Kind.ByRef2: + type = type.MakeByRefType(); + break; + } + } + return type; + } + } + + // Token: 0x02000054 RID: 84 + internal struct ElementedTypeDescrItem // \u000E\u2005 + { + internal enum Kind { Ponter0, Array1, ByRef2 } + + // Token: 0x04000183 RID: 387 + public Kind K; // \u0002 + + // Token: 0x04000184 RID: 388 + public int ArrayRank; // \u0003 + } +}
\ No newline at end of file diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/MyBuffer.cs b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/MyBuffer.cs new file mode 100644 index 0000000..6fd4104 --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/MyBuffer.cs @@ -0,0 +1,569 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; + +namespace UnitTestProject.RefVm +{ + // Token: 0x02000024 RID: 36 + internal sealed class MyBuffer : IDisposable // \u0005\u2007 + { + // Token: 0x060000F2 RID: 242 RVA: 0x000051C8 File begin: 0x000033C8 + public MyBuffer() : this(0) + { + } + + // Token: 0x060000F3 RID: 243 RVA: 0x000051D4 File begin: 0x000033D4 + public MyBuffer(int sz) + { + if (sz < 0) + { + throw new ArgumentOutOfRangeException(); + } + _data = new byte[sz]; + _size = sz; + _internal = true; + _writable = true; + _begin = 0; + _valid = true; + } + + // Token: 0x060000F4 RID: 244 RVA: 0x00005220 File begin: 0x00003420 + public MyBuffer(byte[] src) : this(src, true) + { + } + + // Token: 0x060000F5 RID: 245 RVA: 0x0000522C File begin: 0x0000342C + public MyBuffer(byte[] src, bool writable) + { + if (src == null) + { + throw new ArgumentNullException(); + } + _data = src; + _end = (_size = src.Length); + _writable = writable; + _begin = 0; + _valid = true; + } + + // Token: 0x060000F6 RID: 246 RVA: 0x00005278 File begin: 0x00003478 + public MyBuffer(byte[] src, int begin, int count) : this(src, begin, count, true) + { + } + + // Token: 0x060000F7 RID: 247 RVA: 0x00005284 File begin: 0x00003484 + public MyBuffer(byte[] src, int begin, int count, bool writable) + { + if (src == null) + { + throw new ArgumentNullException(); + } + if (begin < 0) + { + throw new ArgumentOutOfRangeException(); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException(); + } + if (src.Length - begin < count) + { + throw new ArgumentException(); + } + _data = src; + _cursor = begin; + _begin = begin; + _end = (_size = begin + count); + _writable = writable; + _internal = false; + _valid = true; + } + + // Token: 0x060000F8 RID: 248 RVA: 0x00005304 File begin: 0x00003504 + public bool IsValid() // \u0002 + { + return _valid; + } + + // Token: 0x060000F9 RID: 249 RVA: 0x0000530C File begin: 0x0000350C + public bool IsValid2() // \u0003 + { + return _valid; + } + + // Token: 0x060000FA RID: 250 RVA: 0x00005314 File begin: 0x00003514 + public bool IsWritable() // \u0005 + { + return _writable; + } + + // Token: 0x060000FB RID: 251 RVA: 0x0000531C File begin: 0x0000351C + public void DoDispose() // \u0002 + { + Dispose(true); + // ReSharper disable once GCSuppressFinalizeForTypeWithoutDestructor + GC.SuppressFinalize(this); + } + + // Token: 0x060000FC RID: 252 RVA: 0x0000532C File begin: 0x0000352C + public void Dispose() + { + Dispose(false); + } + + // Token: 0x060000FD RID: 253 RVA: 0x00005334 File begin: 0x00003534 + private void Dispose(bool disposing) // \u0002 + { + if (!_disposed) + { + if (disposing) + { + _valid = false; + _writable = false; + _internal = false; + } + _disposed = true; + } + } + + // Token: 0x060000FE RID: 254 RVA: 0x00005360 File begin: 0x00003560 + private bool Expand(int newSize) // \u0002 + { + if (newSize < 0) + { + throw new IOException(); + } + if (newSize > _size) + { + if (newSize < 256) + { + newSize = 256; + } + if (newSize < _size * 2) + { + newSize = _size * 2; + } + ExpandExact(newSize); + return true; + } + return false; + } + + // Token: 0x060000FF RID: 255 RVA: 0x000053B0 File begin: 0x000035B0 + public void DoNothing() // \u0003 + {} + + // Token: 0x06000100 RID: 256 RVA: 0x000053B4 File begin: 0x000035B4 + internal byte[] Data() // \u0002 + { + return _data; + } + + // Token: 0x06000101 RID: 257 RVA: 0x000053BC File begin: 0x000035BC + internal void GetRanges(out int begin, out int end) // \u0002 + { + if (!_valid) + { + throw new Exception(); + } + begin = _begin; + end = _end; + } + + // Token: 0x06000102 RID: 258 RVA: 0x000053DC File begin: 0x000035DC + internal int GetCursor() // \u0002 + { + if (!_valid) + { + throw new Exception(); + } + return _cursor; + } + + // Token: 0x06000103 RID: 259 RVA: 0x000053F4 File begin: 0x000035F4 + public int SkipBytes(int cnt) // \u0002 + { + if (!_valid) + { + throw new Exception(); + } + var num = _end - _cursor; + if (num > cnt) + { + num = cnt; + } + if (num < 0) + { + num = 0; + } + _cursor += num; + return num; + } + + // Token: 0x06000104 RID: 260 RVA: 0x00005438 File begin: 0x00003638 + public int Capacity() // \u0003 + { + if (!_valid) + { + throw new Exception(); + } + return _size - _begin; + } + + // Token: 0x06000105 RID: 261 RVA: 0x00005458 File begin: 0x00003658 + public void ExpandExact(int newSize) // \u0002 + { + if (!_valid) + { + throw new Exception(); + } + if (newSize != _size) + { + if (!_internal) + { + throw new Exception(); + } + if (newSize < _end) + { + throw new ArgumentOutOfRangeException(); + } + if (newSize > 0) + { + var dst = new byte[newSize]; + if (_end > 0) + { + Buffer.BlockCopy(_data, 0, dst, 0, _end); + } + _data = dst; + } + else + { + _data = null; + } + _size = newSize; + } + } + + // Token: 0x06000106 RID: 262 RVA: 0x000054D8 File begin: 0x000036D8 + public long UsedSize() // \u0002 + { + if (!_valid) + { + throw new Exception(); + } + return _end - _begin; + } + + // Token: 0x06000107 RID: 263 RVA: 0x000054F8 File begin: 0x000036F8 + public long GetPos() // \u0003 + { + if (!_valid) + { + throw new Exception(); + } + return _cursor - _begin; + } + + // Token: 0x06000108 RID: 264 RVA: 0x00005518 File begin: 0x00003718 + public void SetPos(long newPos) // \u0002 + { + if (!_valid) + { + throw new Exception(); + } + if (newPos < 0L) + { + throw new ArgumentOutOfRangeException(); + } + if (newPos > 2147483647L) + { + throw new ArgumentOutOfRangeException(); + } + _cursor = _begin + (int)newPos; + } + + // Token: 0x06000109 RID: 265 RVA: 0x00005554 File begin: 0x00003754 + public int Read([In] [Out] byte[] dest, int offset, int cnt) // \u0002 + { + if (!_valid) + { + throw new Exception(); + } + if (dest == null) + { + throw new ArgumentNullException(); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException(); + } + if (cnt < 0) + { + throw new ArgumentOutOfRangeException(); + } + if (dest.Length - offset < cnt) + { + throw new ArgumentException(); + } + var num = _end - _cursor; + if (num > cnt) + { + num = cnt; + } + if (num <= 0) + { + return 0; + } + if (num <= 8) + { + var num2 = num; + while (--num2 >= 0) + { + dest[offset + num2] = _data[_cursor + num2]; + } + } + else + { + Buffer.BlockCopy(_data, _cursor, dest, offset, num); + } + _cursor += num; + return num; + } + + // Token: 0x0600010A RID: 266 RVA: 0x00005600 File begin: 0x00003800 + public int ReadByte() // \u0005 + { + if (!_valid) + { + throw new Exception(); + } + if (_cursor >= _end) + { + return -1; + } + var num = _cursor; + _cursor = num + 1; + return _data[num]; + } + + // Token: 0x0600010B RID: 267 RVA: 0x00005644 File begin: 0x00003844 + public long Seek(long distance, SeekOrigin org) // \u0002 + { + if (!_valid) + { + throw new Exception(); + } + if (distance > 2147483647L) + { + throw new ArgumentOutOfRangeException(); + } + switch (org) + { + case SeekOrigin.Begin: + if (distance < 0L) + { + throw new IOException(); + } + _cursor = _begin + (int)distance; + break; + case SeekOrigin.Current: + if (distance + _cursor < _begin) + { + throw new IOException(); + } + _cursor += (int)distance; + break; + case SeekOrigin.End: + if (_end + distance < _begin) + { + throw new IOException(); + } + _cursor = _end + (int)distance; + break; + default: + throw new ArgumentException(); + } + return _cursor; + } + + // Token: 0x0600010C RID: 268 RVA: 0x00005700 File begin: 0x00003900 + public void LazyShrink(long newCount) // \u0003 +{ + if (!_writable) + { + throw new Exception(); + } + if (newCount > 2147483647L) + { + throw new ArgumentOutOfRangeException(); + } + if (newCount < 0L || newCount > 2147483647 - _begin) + { + throw new ArgumentOutOfRangeException(); + } + var num = _begin + (int)newCount; + if (!Expand(num) && num > _end) + { + Array.Clear(_data, _end, num - _end); + } + _end = num; + if (_cursor > num) + { + _cursor = num; + } + } + + // Token: 0x0600010D RID: 269 RVA: 0x00005794 File begin: 0x00003994 + public byte[] ToArray() // \u0003 + { + var array = new byte[_end - _begin]; + Buffer.BlockCopy(_data, _begin, array, 0, _end - _begin); + return array; + } + + // Token: 0x0600010E RID: 270 RVA: 0x000057D8 File begin: 0x000039D8 + public void Write(byte[] src, int offset, int cnt) // \u0002 + { + if (!_valid) + { + throw new Exception(); + } + if (!_writable) + { + throw new Exception(); + } + if (src == null) + { + throw new ArgumentNullException(); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException(); + } + if (cnt < 0) + { + throw new ArgumentOutOfRangeException(); + } + if (src.Length - offset < cnt) + { + throw new ArgumentException(); + } + var num = _cursor + cnt; + if (num < 0) + { + throw new IOException(); + } + if (num > _end) + { + var flag = _cursor > _end; + if (num > _size && Expand(num)) + { + flag = false; + } + if (flag) + { + Array.Clear(_data, _end, num - _end); + } + _end = num; + } + if (cnt <= 8) + { + while (--cnt >= 0) + { + _data[_cursor + cnt] = src[offset + cnt]; + } + } + else + { + Buffer.BlockCopy(src, offset, _data, _cursor, cnt); + } + _cursor = num; + } + + // Token: 0x0600010F RID: 271 RVA: 0x000058D0 File begin: 0x00003AD0 + public void AppendByte(byte b) // \u0002 + { + if (!_valid) + { + throw new Exception(); + } + if (!_writable) + { + throw new Exception(); + } + if (_cursor >= _end) + { + var num = _cursor + 1; + var flag = _cursor > _end; + if (num >= _size && Expand(num)) + { + flag = false; + } + if (flag) + { + Array.Clear(_data, _end, _cursor - _end); + } + _end = num; + } + _data[_cursor] = b; + _cursor++; + } + + // Token: 0x06000110 RID: 272 RVA: 0x00005974 File begin: 0x00003B74 + public void WriteTo(Stream s) // \u0002 + { + if (!_valid) + { + throw new Exception(); + } + if (s == null) + { + throw new ArgumentNullException(); + } + s.Write(_data, _begin, _end - _begin); + } + + // Token: 0x06000111 RID: 273 RVA: 0x000059AC File begin: 0x00003BAC + internal int ReadInt32() // \u0008 + { + if (!_valid) + { + throw new Exception(); + } + var num = _cursor += 4; + if (num > _end) + { + _cursor = _end; + throw new Exception(); + } + return _data[num - 2] | _data[num - 3] << 24 | _data[num - 1] << 8 | _data[num - 4] << 16; + } + + // Token: 0x04000034 RID: 52 + private byte[] _data; // \u0002 + + // Token: 0x04000035 RID: 53 + private readonly int _begin; // \u0003 + + // Token: 0x04000036 RID: 54 + private int _cursor; // \u0005 + + // Token: 0x04000037 RID: 55 + private int _end; // \u0008 + + // Token: 0x04000038 RID: 56 + private int _size; // \u0006 + + // Token: 0x04000039 RID: 57 + private bool _internal; // \u000E + + // Token: 0x0400003A RID: 58 + private bool _writable; // \u000F + + // Token: 0x0400003B RID: 59 + private bool _valid; // \u0002\u2000 + + // Token: 0x0400003C RID: 60 + private bool _disposed; // \u0003\u2000 + } +} diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/MyBufferReader.cs b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/MyBufferReader.cs new file mode 100644 index 0000000..58226bb --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/MyBufferReader.cs @@ -0,0 +1,563 @@ +using System; +using System.IO; +using System.Text; +using forms_cil; + +namespace UnitTestProject.RefVm +{ + // Token: 0x0200000A RID: 10 + internal sealed class MyBufferReader : IDisposable // \u0002\u2007 + { + // Token: 0x0400000C RID: 12 + private MyBuffer _src; // \u0002 + + // Token: 0x0400000D RID: 13 + private byte[] _inputRawBuf; // \u0003 + + // Token: 0x0400000E RID: 14 + private Decoder _decoder; // \u0005 + + // Token: 0x0400000F RID: 15 + private byte[] _inputCharRawBuf; // \u0008 + + // Token: 0x04000010 RID: 16 + private char[] _inputCharsDecoded; // \u0006 + + // Token: 0x04000011 RID: 17 + private char[] _stringChunk; // \u000E + + // Token: 0x04000012 RID: 18 + private readonly int _maxCharsIn128Bytes; // \u000F + + // Token: 0x04000013 RID: 19 + private readonly bool _isUnicode; // \u0002\u2000 + + // Token: 0x04000014 RID: 20 + private readonly bool _alwaysTrue; // \u0003\u2000 + + // Token: 0x06000034 RID: 52 RVA: 0x000027C8 File Offset: 0x000009C8 + public MyBufferReader(MyBuffer src) : this(src, new UTF8Encoding()) + { + } + + // Token: 0x06000035 RID: 53 RVA: 0x000027D8 File Offset: 0x000009D8 + private MyBufferReader(MyBuffer src, Encoding encoding) + { + if (src == null) + { + throw new ArgumentNullException(); + } + if (encoding == null) + { + throw new ArgumentNullException(); + } + if (!src.IsValid()) + { + throw new ArgumentException(); + } + _src = src; + _decoder = encoding.GetDecoder(); + _maxCharsIn128Bytes = encoding.GetMaxCharCount(128); + var num = encoding.GetMaxByteCount(1); + if (num < 16) + num = 16; + _inputRawBuf = new byte[num]; + _stringChunk = null; + _inputCharRawBuf = null; + _isUnicode = (encoding is UnicodeEncoding); + _alwaysTrue = (_src != null); + } + + // Token: 0x06000036 RID: 54 RVA: 0x00002878 File Offset: 0x00000A78 + public MyBuffer GetBuffer() // \u0002 + { + return _src; + } + + // Token: 0x06000037 RID: 55 RVA: 0x00002880 File Offset: 0x00000A80 + public void Dispose() // \u0002 + { + DoDispose(true); + } + + // Token: 0x06000038 RID: 56 RVA: 0x0000288C File Offset: 0x00000A8C + private void DoDispose(bool disposing) // \u0002 + { + if (disposing) + _src?.DoDispose(); + _src = null; + _inputRawBuf = null; + _decoder = null; + _inputCharRawBuf = null; + _inputCharsDecoded = null; + _stringChunk = null; + } + + // Token: 0x06000039 RID: 57 RVA: 0x000028E0 File Offset: 0x00000AE0 + void IDisposable.Dispose() // \u0002\u2007\u2008\u2000\u2002\u200A\u0003 + { + DoDispose(true); + } + + // Token: 0x0600003A RID: 58 RVA: 0x000028EC File Offset: 0x00000AEC + public int PeekUnicodeChar() // \u0002 + { + SrcPrecondition(); + if (!_src.IsValid2()) + { + return -1; + } + var pos = _src.GetPos(); + var ret = SafeReadUnicodeChar(); + _src.SetPos(pos); + return ret; + } + + // Token: 0x06000051 RID: 81 RVA: 0x00002FE8 File Offset: 0x000011E8 + private void SrcPrecondition() // \u0005 + { + if (_src == null) + { + throw new Exception(); + } + } + + // Token: 0x0600003B RID: 59 RVA: 0x0000292C File Offset: 0x00000B2C + public int SafeReadUnicodeChar() // \u0003 + { + SrcPrecondition(); + return ReadUnicodeChar(); + } + + // Token: 0x0600004E RID: 78 RVA: 0x00002E38 File Offset: 0x00001038 + private int ReadUnicodeChar() // \u0005 + { + var charCnt = 0; + var savedPos = 0L; + if (_src.IsValid2()) + { + savedPos = _src.GetPos(); + } + if (_inputCharRawBuf == null) + { + _inputCharRawBuf = new byte[128]; + } + if (_inputCharsDecoded == null) + { + _inputCharsDecoded = new char[1]; + } + while (charCnt == 0) + { + var bytesToRead = _isUnicode ? 2 : 1; + var b = _src.ReadByte(); + _inputCharRawBuf[0] = (byte)b; + if (b == -1) + { + bytesToRead = 0; + } + if (bytesToRead == 2) + { + b = _src.ReadByte(); + _inputCharRawBuf[1] = (byte)b; + if (b == -1) + { + bytesToRead = 1; + } + } + if (bytesToRead == 0) + { + return -1; + } + try + { + charCnt = _decoder.GetChars(_inputCharRawBuf, 0, bytesToRead, _inputCharsDecoded, 0); + } + catch + { + if (_src.IsValid2()) + { + _src.Seek(savedPos - _src.GetPos(), SeekOrigin.Current); + } + throw; + } + } + if (charCnt == 0) + { + return -1; + } + return _inputCharsDecoded[0]; + } + + // Token: 0x06000053 RID: 83 RVA: 0x0000305C File Offset: 0x0000125C + private void ReadToRawBuf(int cnt) // \u0002 + { + SrcPrecondition(); + var offset = 0; + int bytesRead; + if (cnt != 1) + { + while (true) + { + bytesRead = _src.Read(_inputRawBuf, offset, cnt - offset); + if (bytesRead == 0) + break; + offset += bytesRead; + if (offset >= cnt) + return; + } + throw new Exception(); + } + bytesRead = _src.ReadByte(); + if (bytesRead == -1) + { + throw new Exception(); + } + _inputRawBuf[0] = (byte)bytesRead; + } + + // Token: 0x0600003C RID: 60 RVA: 0x0000293C File Offset: 0x00000B3C + public bool ReadByteInternal() // \u0002 + { + ReadToRawBuf(1); + return _inputRawBuf[0] > 0; + } + + // Token: 0x0600003D RID: 61 RVA: 0x00002950 File Offset: 0x00000B50 + public byte ReadByte() // \u0002 + { + SrcPrecondition(); + var b = _src.ReadByte(); + if (b == -1) + { + throw new Exception(); + } + return (byte)b; + } + + // Token: 0x0600003E RID: 62 RVA: 0x00002970 File Offset: 0x00000B70 + public sbyte ReadSbyte() // \u0002 + { + ReadToRawBuf(1); + return (sbyte)_inputRawBuf[0]; + } + + // Token: 0x0600003F RID: 63 RVA: 0x00002984 File Offset: 0x00000B84 + public char ReadChar() // \u0002 + { + var c = SafeReadUnicodeChar(); + if (c == -1) + { + throw new Exception(); + } + return (char)c; + } + + // Token: 0x06000040 RID: 64 RVA: 0x00002998 File Offset: 0x00000B98 + public short ReadShort() // \u0002 + { + ReadToRawBuf(2); + return (short)(_inputRawBuf[0] | _inputRawBuf[1] << 8); + } + + // Token: 0x06000041 RID: 65 RVA: 0x000029B8 File Offset: 0x00000BB8 + public ushort ReadUshort() // \u0002 + { + ReadToRawBuf(2); + return (ushort)(_inputRawBuf[0] | _inputRawBuf[1] << 8); + } + + // Token: 0x06000042 RID: 66 RVA: 0x000029D8 File Offset: 0x00000BD8 + public uint ReadUint() // \u0002 + { + ReadToRawBuf(4); + return (uint)(_inputRawBuf[0] | _inputRawBuf[1] << 8 | _inputRawBuf[2] << 16 | _inputRawBuf[3] << 24); + } + + // Token: 0x06000043 RID: 67 RVA: 0x00002A0C File Offset: 0x00000C0C + public long ReadLong() // \u0002 + { + ReadToRawBuf(8); + var num = (uint)(_inputRawBuf[0] | _inputRawBuf[1] << 8 | _inputRawBuf[2] << 16 | _inputRawBuf[3] << 24); + return (long)((ulong)(_inputRawBuf[4] | _inputRawBuf[5] << 8 | _inputRawBuf[6] << 16 | _inputRawBuf[7] << 24) << 32 | num); + } + + // Token: 0x06000044 RID: 68 RVA: 0x00002A80 File Offset: 0x00000C80 + public ulong ReadUlong() // \u0002 + { + ReadToRawBuf(8); + var num = (uint)(_inputRawBuf[0] | _inputRawBuf[1] << 8 | _inputRawBuf[2] << 16 | _inputRawBuf[3] << 24); + return (ulong)(_inputRawBuf[4] | _inputRawBuf[5] << 8 | _inputRawBuf[6] << 16 | _inputRawBuf[7] << 24) << 32 | num; + } + + // Token: 0x06000045 RID: 69 RVA: 0x00002AF4 File Offset: 0x00000CF4 + private BinaryReader ReaderFor(int cnt) // \u0002 + { + ReadToRawBuf(cnt); + return new BinaryReader(new MemoryStream(_inputRawBuf, 0, cnt, false)); + } + + // Token: 0x06000046 RID: 70 RVA: 0x00002B10 File Offset: 0x00000D10 + public float ReadFloat() // \u0002 + { + var r = ReaderFor(4); + var result = r.ReadSingle(); + r.Close(); + return result; + } + + // Token: 0x06000047 RID: 71 RVA: 0x00002B34 File Offset: 0x00000D34 + public double ReadDouble() // \u0002 + { + var r = ReaderFor(8); + var result = r.ReadDouble(); + r.Close(); + return result; + } + + // Token: 0x06000048 RID: 72 RVA: 0x00002B58 File Offset: 0x00000D58 + private static decimal CreateDecimal(int lo, int mid, int hi, int scaleNeg) // \u0002 + { + var isNegative = (scaleNeg & -2147483648) != 0; + var scale = (byte)(scaleNeg >> 16); + return new decimal(lo, mid, hi, isNegative, scale); + } + + // Token: 0x06000049 RID: 73 RVA: 0x00002B80 File Offset: 0x00000D80 + internal static decimal CreateDecimal(byte[] b) // b + { + var lo = b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24; + var mid = b[4] | b[5] << 8 | b[6] << 16 | b[7] << 24; + var hi = b[8] | b[9] << 8 | b[10] << 16 | b[11] << 24; + var scaleNeg = b[12] | b[13] << 8 | b[14] << 16 | b[15] << 24; + return CreateDecimal(lo, mid, hi, scaleNeg); + } + + // Token: 0x0600004A RID: 74 RVA: 0x00002BFC File Offset: 0x00000DFC + public decimal ReadDecimal() // \u0002 + { + ReadToRawBuf(16); + return CreateDecimal(_inputRawBuf); + } + + // Token: 0x0600004B RID: 75 RVA: 0x00002C14 File Offset: 0x00000E14 + public string ReadString() // \u0002 + { + var totalRead = 0; + SrcPrecondition(); + var strLen = Read28Bit(); + if (strLen < 0) + { + throw new IOException(); + } + if (strLen == 0) + { + return string.Empty; + } + if (_inputCharRawBuf == null) + { + _inputCharRawBuf = new byte[128]; + } + if (_stringChunk == null) + { + _stringChunk = new char[_maxCharsIn128Bytes]; + } + StringBuilder stringBuilder = null; + while (true) + { + var needChunkCnt = (strLen - totalRead > 128) ? 128 : (strLen - totalRead); + var realChunkRead = _src.Read(_inputCharRawBuf, 0, needChunkCnt); + if (realChunkRead == 0) + { + break; + } + var chars = _decoder.GetChars(_inputCharRawBuf, 0, realChunkRead, _stringChunk, 0); + if (totalRead == 0 && realChunkRead == strLen) + { + return new string(_stringChunk, 0, chars); + } + if (stringBuilder == null) + { + stringBuilder = new StringBuilder(strLen); + } + stringBuilder.Append(_stringChunk, 0, chars); + totalRead += realChunkRead; + if (totalRead >= strLen) + { + return stringBuilder.ToString(); + } + } + throw new Exception(); + } + + // Token: 0x0600004C RID: 76 RVA: 0x00002D08 File Offset: 0x00000F08 + public int Read(char[] dest, int offset, int cnt) // \u0002 + { + if (dest == null) + { + throw new ArgumentNullException(StringDecryptor.GetString(-1550347170), /* \u0002 */ + StringDecryptor.GetString(-1550347157) /* ArgumentNull_Buffer */); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException(); + } + if (cnt < 0) + { + throw new ArgumentOutOfRangeException(); + } + if (dest.Length - offset < cnt) + { + throw new ArgumentException(); + } + SrcPrecondition(); + return DoRead(dest, offset, cnt); + } + + // Token: 0x0600004D RID: 77 RVA: 0x00002D64 File Offset: 0x00000F64 + private int DoRead(char[] dest, int offset, int cnt) // \u0003 + { + var remainCharsToRead = cnt; + if (_inputCharRawBuf == null) + { + _inputCharRawBuf = new byte[128]; + } + while (remainCharsToRead > 0) + { + var chunkSize = remainCharsToRead; + if (_isUnicode) + { + chunkSize <<= 1; + } + if (chunkSize > 128) + { + chunkSize = 128; + } + int chars; + if (_alwaysTrue) + { + var byteIndex = _src.GetCursor(); + chunkSize = _src.SkipBytes(chunkSize); + if (chunkSize == 0) + { + return cnt - remainCharsToRead; + } + chars = _decoder.GetChars(_src.Data(), byteIndex, chunkSize, dest, offset); + } + else + { + chunkSize = _src.Read(_inputCharRawBuf, 0, chunkSize); + if (chunkSize == 0) + { + return cnt - remainCharsToRead; + } + chars = _decoder.GetChars(_inputCharRawBuf, 0, chunkSize, dest, offset); + } + remainCharsToRead -= chars; + offset += chars; + } + return cnt; + } + + + // Token: 0x0600004F RID: 79 RVA: 0x00002F54 File Offset: 0x00001154 + public char[] ReadChars(int cnt) // \u0002 + { + SrcPrecondition(); + if (cnt < 0) + { + throw new ArgumentOutOfRangeException(); + } + var ret = new char[cnt]; + var realLength = DoRead(ret, 0, cnt); + if (realLength != cnt) + { + var shrinked = new char[realLength]; + Buffer.BlockCopy(ret, 0, shrinked, 0, 2 * realLength); + ret = shrinked; + } + return ret; + } + + // Token: 0x06000050 RID: 80 RVA: 0x00002F9C File Offset: 0x0000119C + public int Read(byte[] dest, int offset, int cnt) // dest + { + if (dest == null) + { + throw new ArgumentNullException(); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException(); + } + if (cnt < 0) + { + throw new ArgumentOutOfRangeException(); + } + if (dest.Length - offset < cnt) + { + throw new ArgumentException(); + } + SrcPrecondition(); + return _src.Read(dest, offset, cnt); + } + + // Token: 0x06000052 RID: 82 RVA: 0x00002FF8 File Offset: 0x000011F8 + public byte[] ReadBytes(int cnt) // \u0002 + { + if (cnt < 0) + { + throw new ArgumentOutOfRangeException(); + } + SrcPrecondition(); + var ret = new byte[cnt]; + var offset = 0; + do + { + var chunkSize = _src.Read(ret, offset, cnt); + if (chunkSize == 0) + { + break; + } + offset += chunkSize; + cnt -= chunkSize; + } + while (cnt > 0); + if (offset != ret.Length) + { + var shrinked = new byte[offset]; + Buffer.BlockCopy(ret, 0, shrinked, 0, offset); + ret = shrinked; + } + return ret; + } + + // Token: 0x06000054 RID: 84 RVA: 0x000030C0 File Offset: 0x000012C0 + internal int Read28Bit() // \u0008 + { + var ret = 0; + var bitCnt = 0; + while (bitCnt != 35) + { + var b = ReadByte(); + ret |= (b & 127) << bitCnt; + bitCnt += 7; + if ((b & 128) == 0) + { + return ret; + } + } + throw new FormatException(); + } + + // Token: 0x06000055 RID: 85 RVA: 0x00003100 File Offset: 0x00001300 + public int ReadInt32() // \u0006 + { + if (_alwaysTrue) + { + return _src.ReadInt32(); + } + ReadToRawBuf(4); + return _inputRawBuf[3] << 8 | _inputRawBuf[1] << 24 | _inputRawBuf[0] << 16 | _inputRawBuf[2]; + } + } +} diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/MyCollection.cs b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/MyCollection.cs new file mode 100644 index 0000000..38766d7 --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/MyCollection.cs @@ -0,0 +1,361 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; + +namespace UnitTestProject.RefVm +{ + // Token: 0x02000006 RID: 6 + internal static class EmptyArray<T> // \u0002\u2003 + { + // Token: 0x04000004 RID: 4 + public static readonly T[] Data = new T[0]; + } + + // Token: 0x02000022 RID: 34 + internal sealed class MyCollection<T> : IEnumerable<T>, ICollection // \u0005\u2006 + { + // Token: 0x0400002C RID: 44 + internal T[] Data; // \u0002 + + // Token: 0x0400002E RID: 46 + internal int ChangeCounter; // \u0005 + + // Token: 0x0400002F RID: 47 + private object _sync; // \u0008 + + // Token: 0x060000DA RID: 218 RVA: 0x00004B9C File Offset: 0x00002D9C + public MyCollection() + { + Data = EmptyArray<T>.Data; + Count = 0; + ChangeCounter = 0; + } + + // Token: 0x060000DB RID: 219 RVA: 0x00004BC0 File Offset: 0x00002DC0 + public MyCollection(int capacity) + { + if (capacity < 0) + { + throw new ArgumentOutOfRangeException(); + } + Data = new T[capacity]; + Count = 0; + ChangeCounter = 0; + } + + // Token: 0x060000DC RID: 220 RVA: 0x00004BEC File Offset: 0x00002DEC + public MyCollection(IEnumerable<T> src) + { + if (src == null) + { + throw new ArgumentNullException(); + } + var collection = src as ICollection<T>; + if (collection != null) + { + var count = collection.Count; + Data = new T[count]; + collection.CopyTo(Data, 0); + Count = count; + return; + } + Count = 0; + Data = new T[4]; + foreach (var i in Data) + { + PushBack(i); + } + } + + // Token: 0x0400002D RID: 45 + // Token: 0x17000006 RID: 6 + // (get) Token: 0x060000DD RID: 221 RVA: 0x00004C88 File Offset: 0x00002E88 + public int Count { get; private set; } // \u0003 + + // Token: 0x060000DE RID: 222 RVA: 0x00004C90 File Offset: 0x00002E90 + bool ICollection.IsSynchronized => false; // \u0005\u2006\u2008\u2000\u2002\u200A\u0002 + + // Token: 0x060000DF RID: 223 RVA: 0x00004C94 File Offset: 0x00002E94 + object ICollection.SyncRoot // \u0005\u2006\u2008\u2000\u2002\u200A\u0002 + { + get + { + if (_sync == null) + { + Interlocked.CompareExchange(ref _sync, new object(), null); + } + return _sync; + } + } + + // Token: 0x060000E0 RID: 224 RVA: 0x00004CB8 File Offset: 0x00002EB8 + public void Clear() // \u0002 + { + Array.Clear(Data, 0, Count); + Count = 0; + ChangeCounter++; + } + + // Token: 0x060000E1 RID: 225 RVA: 0x00004CE4 File Offset: 0x00002EE4 + public bool Contains(T what) // \u0002 + { + var num = Count; + var @default = EqualityComparer<T>.Default; + while (num-- > 0) + { + if (what == null) + { + if (Data[num] == null) + { + return true; + } + } + else if (Data[num] != null && @default.Equals(Data[num], what)) + { + return true; + } + } + return false; + } + + // Token: 0x060000E2 RID: 226 RVA: 0x00004D50 File Offset: 0x00002F50 + public void CopyTo(T[] dest, int offset) // \u0003 + { + if (dest == null) + { + throw new ArgumentNullException(StringDecryptor.GetString(-1550346880) /* \u0002 */); + } + if (offset < 0 || offset > dest.Length) + { + throw new ArgumentOutOfRangeException(StringDecryptor.GetString(-1550346867) /* \u0003 */, + StringDecryptor.GetString(-1550346858) /* arrayIndex < 0 || arrayIndex > array.Length */); + } + if (dest.Length - offset < Count) + { + throw new ArgumentException(StringDecryptor.GetString(-1550347192) /* Invalid Off Len */); + } + Array.Copy(Data, 0, dest, offset, Count); + Array.Reverse(dest, offset, Count); + } + + // Token: 0x060000E3 RID: 227 RVA: 0x00004DD4 File Offset: 0x00002FD4 + void ICollection.CopyTo(Array dest, int offset) // \u0005\u2006\u2008\u2000\u2002\u200A\u0002 + { + if (dest == null) + { + throw new ArgumentNullException(); + } + if (dest.Rank != 1) + { + throw new ArgumentException(); + } + if (dest.GetLowerBound(0) != 0) + { + throw new ArgumentException(); + } + if (offset < 0 || offset > dest.Length) + { + throw new ArgumentOutOfRangeException(); + } + if (dest.Length - offset < Count) + { + throw new ArgumentException(); + } + try + { + Array.Copy(Data, 0, dest, offset, Count); + Array.Reverse(dest, offset, Count); + } + catch (ArrayTypeMismatchException) + { + throw new ArgumentException(); + } + } + + // Token: 0x060000E4 RID: 228 RVA: 0x00004E6C File Offset: 0x0000306C + public MyEnumerator<T> GetEnumerator() // \u0005 + { + return new MyEnumerator<T>(this); + } + + // Token: 0x060000E5 RID: 229 RVA: 0x00004E74 File Offset: 0x00003074 + IEnumerator<T> IEnumerable<T>.GetEnumerator() // \u0005\u2006\u2008\u2000\u2002\u200A\u0008 + { + return new MyEnumerator<T>(this); + } + + // Token: 0x060000E6 RID: 230 RVA: 0x00004E84 File Offset: 0x00003084 + IEnumerator IEnumerable.GetEnumerator() // \u0005\u2006\u2008\u2000\u2002\u200A\u0002 + { + return new MyEnumerator<T>(this); + } + + // Token: 0x060000E7 RID: 231 RVA: 0x00004E94 File Offset: 0x00003094 + public void Shrink() // \u0003 + { + var num = (int)(Data.Length * 0.9); + if (Count < num) + { + var destinationArray = new T[Count]; + Array.Copy(Data, 0, destinationArray, 0, Count); + Data = destinationArray; + ChangeCounter++; + } + } + + // Token: 0x060000E8 RID: 232 RVA: 0x00004EF4 File Offset: 0x000030F4 + public T PeekBack() // \u0006 + { + if (Count == 0) + { + throw new InvalidOperationException(); + } + return Data[Count - 1]; + } + + // Token: 0x060000E9 RID: 233 RVA: 0x00004F18 File Offset: 0x00003118 + public T PopBack() // \u000E + { + if (Count == 0) + { + throw new InvalidOperationException(); + } + ChangeCounter++; + var ret = Data[--Count]; + Data[Count] = default(T); + return ret; + } + + // Token: 0x060000EA RID: 234 RVA: 0x00004F78 File Offset: 0x00003178 + public void PushBack(T obj) // \u000F + { + if (Count == Data.Length) + { + var destinationArray = new T[(Data.Length == 0) ? 4 : (2 * Data.Length)]; + Array.Copy(Data, 0, destinationArray, 0, Count); + Data = destinationArray; + } + var num = Count; + Count = num + 1; + Data[num] = obj; + ChangeCounter++; + } + + // Token: 0x060000EB RID: 235 RVA: 0x00004FF8 File Offset: 0x000031F8 + public T[] Reverse() // \u0002\u2000 + { + var array = new T[Count]; + for (var i = 0; i < Count; i++) + { + array[i] = Data[Count - i - 1]; + } + return array; + } + + // Token: 0x02000023 RID: 35 + public struct MyEnumerator<T1> : IEnumerator<T1> // \u0002 + { + // Token: 0x060000EC RID: 236 RVA: 0x00005040 File Offset: 0x00003240 + internal MyEnumerator(MyCollection<T1> src) + { + _src = src; + _changeCounter = _src.ChangeCounter; + _curPos = -2; + _current = default(T1); + } + + // Token: 0x060000ED RID: 237 RVA: 0x00005070 File Offset: 0x00003270 + public void Dispose() + { + _curPos = -1; + } + + // Token: 0x060000EE RID: 238 RVA: 0x0000507C File Offset: 0x0000327C + public bool MoveNext() + { + if (_changeCounter != _src.ChangeCounter) + { + throw new InvalidOperationException(StringDecryptor.GetString(-1550346776) /* EnumFailedVersion */); + } + if (_curPos == -2) + { + _curPos = _src.Count - 1; + if (_curPos < 0) return false; + _current = _src.Data[_curPos]; + return true; + } + if (_curPos == -1) + { + return false; + } + if (--_curPos >= 0) + { + _current = _src.Data[_curPos]; + return true; + } + _current = default(T1); + return false; + } + + // Token: 0x17000007 RID: 7 + // (get) Token: 0x060000EF RID: 239 RVA: 0x00005144 File Offset: 0x00003344 + public T1 Current + { + get + { + if (_curPos == -2) + { + throw new InvalidOperationException(); + } + if (_curPos == -1) + { + throw new InvalidOperationException(); + } + return _current; + } + } + + // Token: 0x060000F0 RID: 240 RVA: 0x0000516C File Offset: 0x0000336C + object IEnumerator.Current // \u0002\u2008\u2000\u2002\u200A\u0002 + { + get + { + if (_curPos == -2) + { + throw new InvalidOperationException(); + } + if (_curPos == -1) + { + throw new InvalidOperationException(); + } + return _current; + } + } + + // Token: 0x060000F1 RID: 241 RVA: 0x00005198 File Offset: 0x00003398 + void IEnumerator.Reset() // \u0002\u2008\u2000\u2002\u200A\u0002 + { + if (_changeCounter != _src.ChangeCounter) + { + throw new InvalidOperationException(); + } + _curPos = -2; + _current = default(T1); + } + + // Token: 0x04000030 RID: 48 + private readonly MyCollection<T1> _src; // \u0002 + + // Token: 0x04000031 RID: 49 + private int _curPos; // \u0003 + + // Token: 0x04000032 RID: 50 + private readonly int _changeCounter; // \u0005 + + // Token: 0x04000033 RID: 51 + private T1 _current; // \u0008 + } + } +} + diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/SdMetadataTokens.cs b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/SdMetadataTokens.cs new file mode 100644 index 0000000..aaf7291 --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/SdMetadataTokens.cs @@ -0,0 +1,288 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; + +namespace UnitTestProject.RefVm +{ + // Token: 0x02000063 RID: 99 + internal static class SdMetadataTokens // \u000F\u2009 + { + // Token: 0x06000399 RID: 921 RVA: 0x00015D18 File Offset: 0x00013F18 + [MethodImpl(MethodImplOptions.NoInlining)] + internal static long GetLong() // \u0002 + { + if (Assembly.GetCallingAssembly() != typeof(SdMetadataTokens).Assembly || !CheckStack()) + { + return 0L; + } + long result; + lock (Obj) + { + var num = Obj.GetLong7(); + if (num == 0L) + { + var executingAssembly = Assembly.GetExecutingAssembly(); + var list = new List<byte>(); + AssemblyName assemblyName; + try + { + assemblyName = executingAssembly.GetName(); + } + catch + { + assemblyName = new AssemblyName(executingAssembly.FullName); + } + var array = assemblyName.GetPublicKeyToken(); + if (array != null && array.Length == 0) + { + array = null; + } + if (array != null) + { + list.AddRange(array); + } + list.AddRange(Encoding.Unicode.GetBytes(assemblyName.Name)); + var num2 = 0x02000063; //GetMdt(typeof(SdMetadataTokens)); + var num3 = Class1.M(); + list.Add((byte)(num2 >> 24)); + list.Add((byte)(num3 >> 16)); + list.Add((byte)(num2 >> 8)); + list.Add((byte)num3); + list.Add((byte)(num2 >> 16)); + list.Add((byte)(num3 >> 8)); + list.Add((byte)num2); + list.Add((byte)(num3 >> 24)); + var count = list.Count; + var num4 = 0uL; + for (var num5 = 0; num5 != count; num5++) + { + num4 += list[num5]; + num4 += num4 << 20; + num4 ^= num4 >> 12; + list[num5] = 0; + } + num4 += num4 << 6; + num4 ^= num4 >> 22; + num4 += num4 << 30; + num = (long)num4; + num ^= 7895633081549295753L; + Obj.SetLong(num); + } + result = num; + } + return result; + } + + // Token: 0x0600039A RID: 922 RVA: 0x00015EE0 File Offset: 0x000140E0 + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool CheckStack() // \u0002 + { + return CheckStackImpl(); + } + + // Token: 0x0600039B RID: 923 RVA: 0x00015EEC File Offset: 0x000140EC + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool CheckStackImpl() // \u0003 + { + var stackTrace = new StackTrace(); + var frame = stackTrace.GetFrame(3); + var methodBase = frame?.GetMethod(); + var type = methodBase?.DeclaringType; + return type != typeof(RuntimeMethodHandle) && type != null && type.Assembly == typeof(SdMetadataTokens).Assembly; + } + + // Token: 0x0600039C RID: 924 RVA: 0x00015F50 File Offset: 0x00014150 + // ReSharper disable once UnusedMember.Local + private static int GetMdt(Type t) // \u0002 + { + return t.MetadataToken; + } + + // Token: 0x0400019A RID: 410 + // \u0002 + private static readonly Class7 Obj = new Class7(); + + // Token: 0x02000064 RID: 100 + public sealed class Class1 // \u0002\u2007\u2007\u2009\u2002\u2006\u2003\u2003\u2002\u2004\u2007\u200A\u2009\u200A\u2008\u200A\u2000\u2003\u200B\u2007\u200A\u2008\u200A\u2003\u2006\u200B + { + // Token: 0x0600039E RID: 926 RVA: 0x00015F60 File Offset: 0x00014160 + [MethodImpl(MethodImplOptions.NoInlining)] + internal static int M() + { + return Class2.M3(Class2.M2(0x02000067 /*GetMdt(typeof(Class4))*/, Class2.M3(0x02000064 /*GetMdt(typeof(Class1))*/, 0x02000066 /*GetMdt(typeof(Class3))*/)), Class5.M1()); + } + } + + // Token: 0x02000065 RID: 101 + private static class Class2 // \u0002\u200A\u2003\u2000\u2002\u2000\u2007\u2008\u2004\u2006\u2007\u2003\u2007\u2004\u2000\u2003\u2009\u2007\u2003\u2006\u2007\u2008\u200A + { + // Token: 0x0600039F RID: 927 RVA: 0x00015FB0 File Offset: 0x000141B0 + internal static int M1(int p1, int p2) // \u0002 + { + return p1 ^ p2 - -~~- -~~- -~~-1683504797; + } + + // Token: 0x060003A0 RID: 928 RVA: 0x00015FC8 File Offset: 0x000141C8 + internal static int M2(int p1, int p2) // \u0003 + { + return p1 - -~-~-~~- -~~-1670271084 ^ p2 + -~-~-~~-~-~699406271; + } + + // Token: 0x060003A1 RID: 929 RVA: 0x00015FF0 File Offset: 0x000141F0 + internal static int M3(int p1, int p2) // \u0005 + { + return p1 ^ p2 - -~~-~-~- -~~-1466097638 ^ p1 - p2; + } + } + + // Token: 0x02000066 RID: 102 + public sealed class Class3 // \u0003\u2001\u2003\u2009\u2009\u2008\u2006\u2006\u2006\u200A\u2003\u2006\u2005\u2005\u2009\u200B\u2009\u200A\u2003\u2007 + { + // Token: 0x060003A3 RID: 931 RVA: 0x00016014 File Offset: 0x00014214 + [MethodImpl(MethodImplOptions.NoInlining)] + internal static int M1() // \u0002 + { + return Class2.M2(Class2.M2(Class6.M1(), Class2.M1(0x02000066 /*GetMdt(typeof(Class3))*/, Class4.M1())), 0x02000068 /*GetMdt(typeof(Class5))*/); + } + } + + // Token: 0x02000067 RID: 103 + public sealed class Class4 // \u0003\u2007\u2006\u2000\u2001\u2003\u2006\u200B\u2003\u2009\u200B\u2008\u200A\u2008\u2004\u2005\u2006\u200A\u2008\u2000\u2000\u200B\u2008\u200A + { + // Token: 0x060003A5 RID: 933 RVA: 0x00016058 File Offset: 0x00014258 + [MethodImpl(MethodImplOptions.NoInlining)] + internal static int M1() // \u0002 + { + return Class2.M1(0x02000069 /*GetMdt(typeof(Class6))*/, 0x0200006B /*GetMdt(typeof(Class8))*/ ^ Class2.M2(0x02000067 /*GetMdt(typeof(Class4))*/, Class2.M3(0x02000068 /*GetMdt(typeof(Class5))*/, Class8.M1()))); + } + } + + // Token: 0x02000068 RID: 104 + public sealed class Class5 // \u0005\u2006\u200A\u2004\u200B\u2005\u200B\u2004\u2005\u2002\u2000\u2001\u2002\u2004\u2000\u2002\u2007\u2003\u2009\u200B\u2007\u200A\u200B\u2000\u2008\u2002\u2003\u2002 + { + // Token: 0x060003A7 RID: 935 RVA: 0x000160C0 File Offset: 0x000142C0 + [MethodImpl(MethodImplOptions.NoInlining)] + internal static int M1() // \u0002 + { + return Class2.M1(0x02000068 /*GetMdt(typeof(Class5))*/, Class2.M3(Class2.M2(0x02000066 /*GetMdt(typeof(Class3))*/, 0x02000064 /*GetMdt(typeof(Class1))*/), Class2.M3(0x02000069 /*GetMdt(typeof(Class6))*/ ^ -~-~~- -~~-1251689633, Class3.M1()))); + } + } + + // Token: 0x02000069 RID: 105 + public sealed class Class6 // \u0008\u2007\u2007\u2004\u2006\u2006\u200A\u2009\u2005\u2006\u2008\u200A\u2000\u200A\u2008\u2002\u2009\u2003\u2006\u2008\u2000\u2005\u2004\u200A\u2004\u2008\u2008\u2001\u2004\u200B + { + // Token: 0x060003A9 RID: 937 RVA: 0x0001613C File Offset: 0x0001433C + [MethodImpl(MethodImplOptions.NoInlining)] + internal static int M1() // \u0002 + { + return Class2.M3(Class2.M1(Class4.M1() ^ ~-~- -~~- -~~-527758448, 0x0200006B /*GetMdt(typeof(Class8))*/), Class2.M2(0x02000064 /*GetMdt(typeof(Class1))*/ ^ 0x02000068 /*GetMdt(typeof(Class5))*/, -~~- -~-~~1892236202)); + } + } + + // Token: 0x0200006A RID: 106 + internal sealed class Class7 // \u000F\u2005\u2007\u2007\u2009\u2009\u2002\u2004\u2008\u2009\u2002\u2000\u2000\u2009\u2009\u200B\u2008\u2004\u2003\u200B\u200A\u2002\u2002\u2003\u2006\u2007\u2000\u2006\u2002\u2003 + { + // Token: 0x060003AA RID: 938 RVA: 0x000161AC File Offset: 0x000143AC + internal Class7() + { + SetLong(0L); + } + + // Token: 0x060003AB RID: 939 RVA: 0x000161BC File Offset: 0x000143BC + [MethodImpl(MethodImplOptions.NoInlining)] + public long GetLong7() // \u0002 + { + if (Assembly.GetCallingAssembly() != typeof(Class7).Assembly) + { + return 2918384L; + } + if (!CheckStack()) + { + return 2918384L; + } + var array = new[] + { + 0, + 0, + 0, + -~~- -~-~~1688528055 + }; + array[1] = ~-~- -~~-~1937298816; + array[2] = ~-~- -~-~~-~-2131774929; + array[0] = ~-~-~- -~~-~859851913; + var num = _i1; + var num2 = _i2; + var num3 = -~-~-~~-~1640531528; + var num4 = -~-~~- -~~-~957401312; + for (var num5 = 0; num5 != 32; num5++) + { + num2 -= (num << 4 ^ num >> 5) + num ^ num4 + array[num4 >> 11 & 3]; + num4 -= num3; + num -= (num2 << 4 ^ num2 >> 5) + num2 ^ num4 + array[num4 & 3]; + } + for (var num6 = 0; num6 != 4; num6++) + { + array[num6] = 0; + } + var num7 = ((ulong)num2 << 32); + var n = (ulong)_i1; + return (long)(num7 | n); + } + + // Token: 0x060003AC RID: 940 RVA: 0x000162D8 File Offset: 0x000144D8 + [MethodImpl(MethodImplOptions.NoInlining)] + internal void SetLong(long p) // \u0002 + { + if (Assembly.GetCallingAssembly() != typeof(Class7).Assembly) + { + return; + } + if (!CheckStack()) + { + return; + } + var array = new int[4]; + array[1] = -~~-~- -~~-~1937298817; + array[0] = -~~-~-~-~859851914; + array[2] = ~-~- -~~-~-2131774930; + array[3] = -~-~~-~- -~~1688528054; + var num = -~-~~- -~-~~1640531529; + var num2 = (int)p; + var num3 = (int)(p >> 32); + var num4 = 0; + for (var num5 = 0; num5 != 32; num5++) + { + num2 += (num3 << 4 ^ num3 >> 5) + num3 ^ num4 + array[num4 & 3]; + num4 += num; + num3 += (num2 << 4 ^ num2 >> 5) + num2 ^ num4 + array[num4 >> 11 & 3]; + } + for (var num6 = 0; num6 != 4; num6++) + { + array[num6] = 0; + } + _i1 = num2; + _i2 = num3; + } + + // Token: 0x0400019B RID: 411 + private int _i1; // \u0002 + + // Token: 0x0400019C RID: 412 + private int _i2; // \u0003 + } + + // Token: 0x0200006B RID: 107 + public sealed class Class8 // \u000F\u200A\u2002\u2009\u2000\u2009\u2003\u200A\u2005\u2001\u2002\u2002\u2003\u200B\u2000\u2009\u2003\u2009\u2009\u2001\u2002\u200B\u2000\u200A + { + // Token: 0x060003AE RID: 942 RVA: 0x000163DC File Offset: 0x000145DC + [MethodImpl(MethodImplOptions.NoInlining)] + internal static int M1() + { + return Class2.M3(0x0200006B /*GetMdt(typeof(Class8))*/, Class2.M1(0x02000064 /*GetMdt(typeof(Class1))*/, Class2.M2(0x02000067 /*GetMdt(typeof(Class4))*/, Class2.M3(0x02000069 /*GetMdt(typeof(Class6))*/, Class2.M1(0x02000066 /*GetMdt(typeof(Class3))*/, 0x02000068 /*GetMdt(typeof(Class5))*/))))); + } + } + } +} diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/SdTemplateStuff.cs b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/SdTemplateStuff.cs new file mode 100644 index 0000000..16f2acf --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/SdTemplateStuff.cs @@ -0,0 +1,180 @@ +using System; +using System.Threading; + +namespace forms_cil +{ + // Token: 0x02000057 RID: 87 + internal interface I4 // \u000E\u2008 + { + // Token: 0x06000346 RID: 838 + bool I4M(); // \u000E\u2008\u2008\u2000\u2002\u200A\u0002 + + // Token: 0x06000347 RID: 839 + object M2(); // \u000E\u2008\u2008\u2000\u2002\u200A\u0002 + + // Token: 0x06000348 RID: 840 + void M3(); // \u000E\u2008\u2008\u2000\u2002\u200A\u0002 + } + + // Token: 0x02000062 RID: 98 + internal interface I5 // \u000F\u2008 + { + // Token: 0x06000397 RID: 919 + void I5M(); // \u000F\u2008\u2008\u2000\u2002\u200A\u0002 + } + + // Token: 0x0200000C RID: 12 + internal interface I1<out T> : I4, I5 // \u0002\u2009 + { + // Token: 0x06000057 RID: 87 + T I1M(); // \u000E\u2008\u2008\u2000\u2002\u200A\u0002 + } + + // Token: 0x0200004B RID: 75 + internal interface I3 // \u0008\u2008 + { + // Token: 0x0600031E RID: 798 + I4 M1(); // \u0008\u2008\u2008\u2000\u2002\u200A\u0002 + } + + // Token: 0x0200003C RID: 60 + internal interface I2<out T> : I3 // \u0006\u2008 + { + // Token: 0x060002CD RID: 717 + I1<T> I2M(); // \u0008\u2008\u2008\u2000\u2002\u200A\u0002 + } + + // Token: 0x02000025 RID: 37 + internal static class SdTemplateStuff // \u0005\u2008 + { + // Token: 0x02000026 RID: 38 + internal sealed class C : I2<int>, I1<int> // \u0002 + { + // Token: 0x06000112 RID: 274 RVA: 0x00005A28 File Offset: 0x00003C28 + public C(int val) + { + _i2 = val; + _i5 = Thread.CurrentThread.ManagedThreadId; + } + + // Token: 0x06000113 RID: 275 RVA: 0x00005A48 File Offset: 0x00003C48 + void I5.I5M() + { + } + + // Token: 0x06000114 RID: 276 RVA: 0x00005A4C File Offset: 0x00003C4C + bool I4.I4M() + { + switch (_i2) + { + case 0: + _i2 = -1; + _i3 = -1496196691; + _i2 = 1; + return true; + case 1: + _i2 = -1; + _i3 = _i8 ^ 70939052; + _i2 = 2; + return true; + case 2: + _i2 = -1; + _i3 = _i8 ^ -1812634754; + _i2 = 3; + return true; + case 3: + _i2 = -1; + _i3 = -5623460; + _i2 = 4; + return true; + case 4: + _i2 = -1; + _i3 = 401181880; + _i2 = 5; + return true; + case 5: + _i2 = -1; + _i3 = 2075948002; + _i2 = 6; + return true; + case 6: + _i2 = -1; + _i3 = _i8 ^ 70939052; + _i2 = 7; + return true; + case 7: + _i2 = -1; + _i3 = -783689628; + _i2 = 8; + return true; + case 8: + _i2 = -1; + _i3 = _i8 ^ 70939052; + _i2 = 9; + return true; + case 9: + _i2 = -1; + return false; + default: + return false; + } + } + + // Token: 0x06000115 RID: 277 RVA: 0x00005BA8 File Offset: 0x00003DA8 + int I1<int>.I1M() + { + return _i3; + } + + // Token: 0x06000116 RID: 278 RVA: 0x00005BB0 File Offset: 0x00003DB0 + void I4.M3() + { + throw new NotSupportedException(); + } + + // Token: 0x06000117 RID: 279 RVA: 0x00005BB8 File Offset: 0x00003DB8 + object I4.M2() + { + return _i3; + } + + // Token: 0x06000118 RID: 280 RVA: 0x00005BC8 File Offset: 0x00003DC8 + I1<int> I2<int>.I2M() + { + C ret; + if (_i2 == -2 && _i5 == Thread.CurrentThread.ManagedThreadId) + { + _i2 = 0; + ret = this; + } + else + { + ret = new C(0); + } + ret._i8 = I6; + return ret; + } + + // Token: 0x06000119 RID: 281 RVA: 0x00005C10 File Offset: 0x00003E10 + I4 I3.M1() + { + return ((I2<int>)this).I2M(); + } + + // Token: 0x0400003D RID: 61 + private int _i2; // \u0002 + + // Token: 0x0400003E RID: 62 + private int _i3; // \u0003 + + // Token: 0x0400003F RID: 63 + private readonly int _i5; // \u0005 + + // Token: 0x04000040 RID: 64 + private int _i8; // \u0008 + + // Token: 0x04000041 RID: 65 + public int I6; // \u0006 + } + } +}
\ No newline at end of file diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/SimpleTypeHelper.cs b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/SimpleTypeHelper.cs new file mode 100644 index 0000000..a062c9e --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/SimpleTypeHelper.cs @@ -0,0 +1,26 @@ +using System; + +namespace UnitTestProject.RefVm +{ + // Token: 0x02000009 RID: 9 + static class SimpleTypeHelper // \u0002\u2006 + { + // Token: 0x06000033 RID: 51 RVA: 0x000027AC File Offset: 0x000009AC + public static bool IsNullableGeneric(Type t) // \u0002 + { + return t.IsGenericType && t.GetGenericTypeDefinition() == NullableType; // \u0003 + } + + // Token: 0x04000008 RID: 8 + public static readonly Type ObjectType = typeof(object); // \u0002 + + // Token: 0x04000009 RID: 9 + private static readonly Type NullableType = typeof(Nullable<>); // \u0003 + + // Token: 0x0400000A RID: 10 + public static readonly Type TypedReferenceType = typeof(TypedReference); // \u0005 + + // Token: 0x0400000B RID: 11 + public static readonly Type EnumType = typeof(Enum); // \u0008 + } +} diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/StringDecryptor.cs b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/StringDecryptor.cs new file mode 100644 index 0000000..f27827b --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/StringDecryptor.cs @@ -0,0 +1,648 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; +using forms_cil; + +// Token: 0x0200003D RID: 61 +namespace UnitTestProject.RefVm +{ + public static class StringDecryptor // \u0006\u2009 + { + private static BinStreamReader _binStreamReader; // \u0003 + private static readonly DecryptedStrings DecryptedStringsGlobal; // \u0002 + private static byte[] _commonKey; // \u0005 + private static short _keyLength; // \u0008 + private static readonly Enum1 Enum1Dummy; // \u0003\u2000 + private static int _int1Dummy; // \u0002\u2000 + private static int _int2Dummy; // \u000F + private static int _int3Dummy; // \u0006 + private static byte[] _pkt; // \u000E + + // Token: 0x060002CE RID: 718 RVA: 0x00013060 File Offset: 0x00011260 + [MethodImpl(MethodImplOptions.NoInlining)] + static StringDecryptor() + { + var num = -42518532; + var num2 = num ^ 1885636661; + DecryptedStringsGlobal = new DecryptedStrings(1970604170 + num + num2 /*9*/); + + var num3 = 2; + var stackTrace = new StackTrace(num3, false); + num3 -= 2; + var frame = stackTrace.GetFrame(num3); + var index = num3; + if (frame == null) + { + stackTrace = new StackTrace(); + index = 1; + frame = stackTrace.GetFrame(index); + } + var num4 = ~- -~~-~-~(1341405001 ^ num ^ num2) ^ -~~- -~-~~(2095196650 + num - num2); + var methodBase = frame?.GetMethod(); + if (frame != null) + { + num4 ^= ~- -~~-~-~(num ^ -1658751032 ^ num2); + } + var type = methodBase?.DeclaringType; + if (type == typeof(RuntimeMethodHandle)) + { + Enum1Dummy = (Enum1)(4 | (int)Enum1Dummy); + num4 ^= 1970604898 + num + num2 + num3; + } + else if (type == null) + { + if (CheckStack(stackTrace, index)) + { + num4 ^= ~-~- -~~-~(-1970628130 - num - num2) - num3; + Enum1Dummy = (Enum1)(16 | (int)Enum1Dummy); + } + else + { + num4 ^= ~- -~~-~-~(num ^ -1885608078 ^ num2); + Enum1Dummy = (Enum1)(1 | (int)Enum1Dummy); + } + } + else + { + num4 ^= ~-~- -~~-~(1885542988 - num + num2) - num3; + Enum1Dummy = (Enum1)(16 | (int)Enum1Dummy); + } + _int1Dummy += num4; + } + + // Token: 0x060002CF RID: 719 RVA: 0x000131D4 File Offset: 0x000113D4 + public static string GetString(int id) // \u0002 + { + lock (DecryptedStringsGlobal) + { + return DecryptedStringsGlobal[id] ?? DecryptString(id, true); + } + } + public static void SetString(int id, string val) // for unit tests + { + lock (DecryptedStringsGlobal) + { + DecryptedStringsGlobal[id] = val; + } + } + + // Token: 0x060002D0 RID: 720 RVA: 0x00013224 File Offset: 0x00011424 + [MethodImpl(MethodImplOptions.NoInlining)] + private static string DecryptString(int id, bool dummy) // \u0002 + { + var num = 1500675437; + var num2 = 1065028357 - num; + byte[] key; + string str; + int num6; + if (_binStreamReader == null) + { + var executingAssembly = Assembly.GetExecutingAssembly(); + _int3Dummy |= num ^ -1084071305 ^ num2; + var stringBuilder = new StringBuilder(); + var num3 = -1821765671 - num + num2; + stringBuilder.Append((char)(num3 >> 16)).Append((char)num3); + num3 = 1822175277 + num ^ num2; + stringBuilder.Append((char)(num3 >> 16)).Append((char)num3); + num3 = (1619914499 ^ num) + num2; + stringBuilder.Append((char)num3).Append((char)(num3 >> 16)); + num3 = 1602104074 - num - num2; + stringBuilder.Append((char)num3).Append((char)(num3 >> 16)); + num3 = (num ^ 1619980037) + num2; + stringBuilder.Append((char)num3).Append((char)(num3 >> 16)); + num3 = num + -1398984659 - num2; + stringBuilder.Append((char)num3).Append((char)(num3 >> 16)); + var manifestResourceStream = executingAssembly.GetManifestResourceStream(/* added by ursoft */ "forms_cil." + + stringBuilder.ToString() + /* added by ursoft */.GetHashCode().ToString()); + var num4 = 2; + var stackTrace = new StackTrace(num4, false); + _int3Dummy ^= (1082521283 ^ num) + num2 | num4; + num4 -= 2; + var frame = stackTrace.GetFrame(num4); + var index = num4; + if (frame == null) + { + stackTrace = new StackTrace(); + index = 1; + frame = stackTrace.GetFrame(index); + } + var methodBase = frame?.GetMethod(); + _int3Dummy ^= num4 + (num + -1936322645 ^ num2); + var type = methodBase?.DeclaringType; + if (frame == null) + { + _int3Dummy ^= 1065247672 - num - num2; + } + var flag = type == typeof(RuntimeMethodHandle); + _int3Dummy ^= (num ^ 1082461797) + num2; + if (!flag) + { + flag = type == null; + if (flag) + { + if (CheckStack(stackTrace, index)) + { + flag = false; + } + else + { + _int3Dummy ^= 1065247640 - num - num2; + } + } + } + if (flag) + { + _int3Dummy ^= 32; + } + _int3Dummy ^= (num ^ 1082521251) + num2 | num4 + 1; + _binStreamReader = new BinStreamReader(manifestResourceStream); + var commonKeyLength = (short)(_binStreamReader.ReadHeaderInt16() ^ ~(short)-(short)-(short)~(short)~(short)-(short)~(short)-(short)~(short)-(short)~(short)(-1065050389 + num ^ num2)); + if (commonKeyLength == 0) + { + _keyLength = (short)(_binStreamReader.ReadHeaderInt16() ^ -(short)~(short)~(short)-(short)-(short)~(short)~(short)-(short)-(short)~(short)~(short)((-1082482306 ^ num) - num2)); + } + else + { + _commonKey = _binStreamReader.Read(commonKeyLength); + } + var assembly = executingAssembly; + var assemblyName = SafeAssemblyName(assembly); + _pkt = SafeAssemblyPkt(assemblyName); + num6 = _int1Dummy; + _int1Dummy = 0; + var num7 = SdMetadataTokens.GetLong(); + num6 ^= (int)(uint)num7; + num6 ^= -888987382 - num + num2; + var num8 = num6; + var num9 = num8; + var num10 = 0; + var num11 = num9 ^ -1693408934 + num - num2; + var num12 = num11 * (1936327810 - num + num2) % ((num ^ -1092770072) - num2); + var num13 = num12; + var obj = ((I2<int>)new SdTemplateStuff.C(-1065028359 + num | num2) + { + I6 = num13 + }).I2M(); + try + { + while (obj.I4M()) + { + var num14 = obj.I1M(); + num12 ^= num10 - num14 << 2; + num10 += num12 >> 3; + } + } + finally + { + obj?.I5M(); + } + num6 ^= ~- -~-~~- -~~(num ^ 1140387705 ^ num2); + var num15 = num12; + num6 = num15 + num6; + _int2Dummy = num6; + _int3Dummy = (_int3Dummy & -1667887203 + num - num2) ^ (num ^ 1082519937) + num2; + if ((Enum1Dummy & (Enum1)(-~~- -~-~~(1936322518 - num ^ num2))) == 0) + { + _int3Dummy = (-1082440641 ^ num) - num2; + } + } + else + { + num6 = _int2Dummy; + } + if (_int3Dummy == 1936366479 - num + num2) + { + return new string(new[] { (char)((-1082462051 ^ num) - num2), '0', (char)(num + -1065028269 + num2) }); + } + var num16 = id ^ -1010833342 ^ num ^ num2 ^ num6; + num16 ^= -1459130838 - num + num2; + _binStreamReader.GetStream().Position = num16; + if (_commonKey != null) + { + key = _commonKey; + } + else + { + short keyLength; + if (_keyLength == -1) + { + keyLength = (short)(_binStreamReader.ReadHeaderInt32() ^ num + -1936293566 - num2 ^ num16); + } + else + { + keyLength = _keyLength; + } + if (keyLength == 0) + { + key = null; + } + else + { + key = _binStreamReader.Read(keyLength); + for (var i = 0; i != key.Length; i = 1 + i) + { + key[i] ^= (byte)(_int2Dummy >> ((3 & i) << 3)); + } + } + } + var stringHeader = _binStreamReader.ReadHeaderInt32() ^ num16 ^ -~~-~-~-~((num ^ -1882046960) + num2) ^ num6; + if (stringHeader != (1936322515 - num | num2)) + { + var flagAnsi = (stringHeader & 211161131 + num - num2) != 0; + var flagCompressed = (stringHeader & (-8713467 - num ^ num2)) != 0; + var flagSecure = (stringHeader & (1619332869 ^ num) + num2) != 0; + stringHeader &= num + -1870334726 ^ num2; + var packedStringBuf = _binStreamReader.Read(stringHeader); + // ReSharper disable once PossibleNullReferenceException + var key1 = key[1]; + var length = packedStringBuf.Length; + var key1XorLen = (byte)(11 + length ^ 7 + key1); + var keysXorLen = (uint)((key[0] | key[2] << 8) + (key1XorLen << 3)); + ushort keysXorLenLowWord = 0; + for (var index = 0; index < length; ++index) + { + if ((index & 1) == 0) + { + keysXorLen = keysXorLen * (uint)((num ^ -1082544904) - num2) + (uint)(num + -1933863442 ^ num2); + keysXorLenLowWord = (ushort)(keysXorLen >> 16); + } + var keysXorLenLowByte = (byte)keysXorLenLowWord; + keysXorLenLowWord = (ushort)(keysXorLenLowWord >> 8); + var inByte = packedStringBuf[index]; + packedStringBuf[index] = (byte)(inByte ^ key1 ^ 3 + key1XorLen ^ keysXorLenLowByte); + key1XorLen = inByte; + } + if (_pkt != null != (_int3Dummy != (-1085052045 ^ num) - num2)) + { + for (var j = 0; j < stringHeader; j = 1 + j) + { + // ReSharper disable once PossibleNullReferenceException + var b5 = _pkt[7 & j]; + b5 = (byte)(b5 << 3 | b5 >> 5); + packedStringBuf[j] ^= b5; + } + } + var num23 = _int3Dummy - 12; + int unpackedLength; + byte[] unpackedStringBuf; + if (!flagCompressed) + { + unpackedLength = stringHeader; + unpackedStringBuf = packedStringBuf; + } + else + { + unpackedLength = packedStringBuf[2] | packedStringBuf[0] << 16 | packedStringBuf[3] << 8 | packedStringBuf[1] << 24; + unpackedStringBuf = new byte[unpackedLength]; + Unpack(packedStringBuf, 4, unpackedStringBuf); + } + if (flagAnsi && num23 == (num + -1935832971 ^ num2)) + { + var chArray = new char[unpackedLength]; + for (var k = 0; k < unpackedLength; k++) + { + chArray[k] = (char)unpackedStringBuf[k]; + } + str = new string(chArray); + } + else + { + str = Encoding.Unicode.GetString(unpackedStringBuf, 0, unpackedStringBuf.Length); + } + num23 += (-1082461318 ^ num) - num2 + (3 & num23) << 5; + if (num23 != (1065521775 - num ^ num2)) + { + var num25 = stringHeader + id ^ -1935385949 + num - num2 ^ (num23 & (-1082460680 ^ num ^ num2)); + var stringBuilder = new StringBuilder(); + var num3 = 1065028445 - num - num2; + stringBuilder.Append((char)(byte)num3); + str = num25.ToString(stringBuilder.ToString()); + } + if (!flagSecure & dummy) + { + str = string.Intern(str); + DecryptedStringsGlobal[id] = str; + if (DecryptedStringsGlobal.GetCachedPairs() == (num + -1936322454 ^ num2)) + { + _binStreamReader.Close(); + _binStreamReader = null; + _commonKey = null; + _pkt = null; + } + } + return str; + } + var refId = _binStreamReader.Read(4); + id = -64102883 ^ num ^ num2 ^ num6; + id = (refId[2] | refId[3] << 16 | refId[0] << 8 | refId[1] << 24) ^ -id; + str = DecryptedStringsGlobal[id]; + return str; + } + + // Token: 0x060002D1 RID: 721 RVA: 0x00013A28 File Offset: 0x00011C28 + private static AssemblyName SafeAssemblyName(Assembly a) // \u0002 + { + AssemblyName result; + try + { + result = a.GetName(); + } + catch + { + result = new AssemblyName(a.FullName); + } + return result; + } + + // Token: 0x060002D2 RID: 722 RVA: 0x00013A60 File Offset: 0x00011C60 + private static byte[] SafeAssemblyPkt(AssemblyName an) // \u0002 + { + var array = an.GetPublicKeyToken(); + if (array != null && array.Length == 0) + { + array = null; + } + return array; + } + + // Token: 0x060002D3 RID: 723 RVA: 0x00013A80 File Offset: 0x00011C80 + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool CheckStack(StackTrace st, int idx) // \u0002 + { + var a = st.GetFrame(idx + 1)?.GetMethod()?.DeclaringType?.Assembly; + if (a != null) + { + var assemblyName = SafeAssemblyName(a); + var array = SafeAssemblyPkt(assemblyName); + if (array != null && array.Length == 8 && array[0] == 183 && array[7] == 137) + { + return true; + } + } + return false; + } + + // Token: 0x060002D4 RID: 724 RVA: 0x00013AF0 File Offset: 0x00011CF0 + private static void Unpack(byte[] packedStringBuf, int idxPacked, byte[] unpackedStringBuf) // \u0002 + { + var idxUnpacked = 0; + var packedBlockHeader = 0; + var byteMask = 0x80; + var unpackLen = unpackedStringBuf.Length; + while (idxUnpacked < unpackLen) + { + byteMask <<= 1; + if (byteMask == 0x100) + { + byteMask = 1; + packedBlockHeader = packedStringBuf[idxPacked++]; + } + if ((packedBlockHeader & byteMask) == 0) + { + unpackedStringBuf[idxUnpacked++] = packedStringBuf[idxPacked++]; + continue; + } + var knownWordLen = (packedStringBuf[idxPacked] >> 2) + 3; + var knownWordOffset = ((packedStringBuf[idxPacked] << 8) | packedStringBuf[idxPacked + 1]) & 0x3ff; + idxPacked += 2; + var knownWordIdx = idxUnpacked - knownWordOffset; + if (knownWordIdx < 0) + return; + while (--knownWordLen >= 0 && idxUnpacked < unpackLen) + { + unpackedStringBuf[idxUnpacked++] = unpackedStringBuf[knownWordIdx++]; + } + } + } + + // Token: 0x0200003E RID: 62 + internal sealed class BinStreamReader // \u0003\u2002\u200A\u2008\u2008\u200B\u2002\u2006\u2002\u2009\u2009\u2006\u2004\u2006\u2002\u2007\u2006\u2003\u2001\u2007\u2003\u200A\u2009\u200B\u2003\u2001 + { + private byte[] _header; // \u0003 + private Stream _stream; // \u0002 + + // Token: 0x060002D5 RID: 725 RVA: 0x00013B94 File Offset: 0x00011D94 + public BinStreamReader(Stream stream) + { + _stream = stream; + _header = new byte[4]; + } + + // Token: 0x060002D6 RID: 726 RVA: 0x00013BB0 File Offset: 0x00011DB0 + public Stream GetStream() // \u0002 + { + return _stream; + } + + // Token: 0x060002D7 RID: 727 RVA: 0x00013BB8 File Offset: 0x00011DB8 + public short ReadHeaderInt16() // \u0002 + { + ReadHeader(2); + return (short) (_header[0] | (_header[1] << 8)); + } + + // Token: 0x060002D8 RID: 728 RVA: 0x00013BD8 File Offset: 0x00011DD8 + public int ReadHeaderInt32() // \u0002 + { + ReadHeader(4); + return _header[0] | (_header[1] << 8) | (_header[2] << 0x10) | (_header[3] << 0x18); + } + + // Token: 0x060002D9 RID: 729 RVA: 0x00013C0C File Offset: 0x00011E0C + private void ThrowEOS() // \u0002 + { + throw new EndOfStreamException(); + } + + // Token: 0x060002DA RID: 730 RVA: 0x00013C14 File Offset: 0x00011E14 + private void ReadHeader(int headerSize) // \u0002 + { + var offset = 0; + int read; + if (headerSize == 1) + { + read = _stream.ReadByte(); + if (read == -1) + ThrowEOS(); + _header[0] = (byte) read; + } + else + { + do + { + read = _stream.Read(_header, offset, headerSize - offset); + if (read == 0) + ThrowEOS(); + offset += read; + } while (offset < headerSize); + } + } + + // Token: 0x060002DB RID: 731 RVA: 0x00013C74 File Offset: 0x00011E74 + public void Close() // \u0003 + { + var stream = _stream; + _stream = null; + stream?.Close(); + _header = null; + } + + // Token: 0x060002DC RID: 732 RVA: 0x00013CA0 File Offset: 0x00011EA0 + public byte[] Read(int bytesCount) // \u0002 + { + if (bytesCount < 0) + throw new ArgumentOutOfRangeException(); + var buffer = new byte[bytesCount]; + var offset = 0; + do + { + var read = _stream.Read(buffer, offset, bytesCount); + if (read == 0) + break; + offset += read; + bytesCount -= read; + } while (bytesCount > 0); + if (offset != buffer.Length) + { + var dst = new byte[offset]; + Buffer.BlockCopy(buffer, 0, dst, 0, offset); + buffer = dst; + } + return buffer; + } + } + + // Token: 0x0200003F RID: 63 + internal sealed class DecryptedStrings // \u0005\u2001\u2007\u200B\u2000\u2008\u2008\u2000\u2000\u2006\u2004\u2008\u200B\u2002\u2006\u200B\u2001\u200B\u2003\u2004\u2001\u2004 + { + private int _cachedPairs; // \u0003 + private Pair[] _arr; // \u0002 + + // Token: 0x060002DD RID: 733 RVA: 0x00013CFC File Offset: 0x00011EFC + public DecryptedStrings() + { + _arr = new Pair[0x10]; + } + + // Token: 0x060002DE RID: 734 RVA: 0x00013D14 File Offset: 0x00011F14 + public DecryptedStrings(int capacityHint) + { + var capacity = 0x10; + capacityHint = capacityHint << 1; + while ((capacity < capacityHint) && (capacity > 0)) + { + capacity = capacity << 1; + } + if (capacity < 0) + { + capacity = 0x10; + } + _arr = new Pair[capacity]; + } + + // Token: 0x060002DF RID: 735 RVA: 0x00013D54 File Offset: 0x00011F54 + public int GetCachedPairs() + { + return _cachedPairs; + } + + // Token: 0x060002E0 RID: 736 RVA: 0x00013D5C File Offset: 0x00011F5C + private void GrowCache() // \u0002 + { + var length = _arr.Length; + var newLength = length * 2; + if (newLength > 0) + { + var newArr = new Pair[newLength]; + var cnt = 0; + for (var i = 0; i < length; i++) + { + if (_arr[i].val != null) + { + var index = _arr[i].id & (newLength - 1); + while (true) + { + if (newArr[index].val == null) + { + newArr[index].val = _arr[i].val; + newArr[index].id = _arr[i].id; + cnt++; + break; + } + index++; + if (index >= newLength) + index = 0; + } + } + } + _arr = newArr; + _cachedPairs = cnt; + } + } + + public string this[int id] + { + // Token: 0x060002E1 RID: 737 RVA: 0x00013E10 File Offset: 0x00012010 + get // \u0002 + { + var length = _arr.Length; + var index = id & (length - 1); + do + { + if (_arr[index].id == id || _arr[index].val == null) + return _arr[index].val; + index++; + if (index >= length) + index = 0; + } while (true); + } + // Token: 0x060002E2 RID: 738 RVA: 0x00013E6C File Offset: 0x0001206C + set // \u0002 + { + var length = _arr.Length; + var halfLength = length >> 1; + var index = id & (length - 1); + do + { + var emptySlot = _arr[index].val == null; + if (_arr[index].id == id || emptySlot) + { + _arr[index].val = value; + if (emptySlot) + { + _arr[index].id = id; + _cachedPairs++; + if (_cachedPairs > halfLength) + GrowCache(); + } + break; + } + index++; + if (index >= length) + index = 0; + } while (true); + } + } + + // Token: 0x02000040 RID: 64 + [StructLayout(LayoutKind.Sequential)] + private struct Pair // \u0002 + { + public int id; + public string val; + } + } + + // Token: 0x02000041 RID: 65 + [Flags] + internal enum Enum1 + { + + } + } +} diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/TypeCompatibility.cs b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/TypeCompatibility.cs new file mode 100644 index 0000000..af9b155 --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/TypeCompatibility.cs @@ -0,0 +1,54 @@ +using System; + +namespace UnitTestProject.RefVm +{ + // Token: 0x02000055 RID: 85 + internal static class TypeCompatibility // \u000E\u2006 + { + // Token: 0x06000341 RID: 833 RVA: 0x000152D4 File Offset: 0x000134D4 + public static bool Check(Type t1, Type t2) // t1 + { + if (t1 == t2) + { + return true; + } + if (t1 == null || t2 == null) + { + return false; + } + if (t1.IsByRef) + { + return t2.IsByRef && Check(t1.GetElementType(), t2.GetElementType()); + } + if (t2.IsByRef) + { + return false; + } + if (t1.IsPointer) + { + return t2.IsPointer && Check(t1.GetElementType(), t2.GetElementType()); + } + if (t2.IsPointer) + { + return false; + } + if (t1.IsArray) + { + return t2.IsArray && t1.GetArrayRank() == t2.GetArrayRank() && Check(t1.GetElementType(), t2.GetElementType()); + } + if (t2.IsArray) + { + return false; + } + if (t1.IsGenericType && !t1.IsGenericTypeDefinition) + { + t1 = t1.GetGenericTypeDefinition(); + } + if (t2.IsGenericType && !t2.IsGenericTypeDefinition) + { + t2 = t2.GetGenericTypeDefinition(); + } + return t1 == t2; + } + } +} diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VariantBase.cs b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VariantBase.cs new file mode 100644 index 0000000..0e60298 --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VariantBase.cs @@ -0,0 +1,2621 @@ +using System; +using System.Linq; +using System.Reflection; + +namespace UnitTestProject.RefVm +{ + // Token: 0x02000059 RID: 89 + internal abstract class VariantBase // \u000F + { + // Token: 0x0600034A RID: 842 + public abstract object GetValueAbstract(); // \u000F\u2008\u2000\u2002\u200A\u0002 + + // Token: 0x0600034B RID: 843 + public abstract void SetValueAbstract(object o); // \u000F\u2008\u2000\u2002\u200A\u0002 + + // Token: 0x0600034C RID: 844 + public enum Vtc + { + Tc0VariantBaseHolder, + Tc1Bool, + Tc2Array, + Tc3Method, + Tc4FieldInfo, + Tc5Enum, + Tc6Char, + Tc7Ulong, + Tc8Float, + Tc9Uint, + Tc10Ushort, + Tc11ValueType, + Tc12Sbyte, + Tc13UIntPtr, + Tc14Byte, + Tc15Short, + Tc16String, + Tc17IntPtr, + Tc18Object, + Tc19Int, + Tc20MdArrayValue, + Tc21Double, + Tc22SdArrayValue, + Tc23LocalsIdxHolder, + Tc24Long + } + + public abstract Vtc GetTypeCode(); // \u000F\u2008\u2000\u2002\u200A\u0002 + + // Token: 0x0600034D RID: 845 + public abstract VariantBase CopyFrom(VariantBase t); // \u000F\u2008\u2000\u2002\u200A\u0002 + + // Token: 0x0600034E RID: 846 + public abstract VariantBase Clone(); // \u000F\u2008\u2000\u2002\u200A\u0002 + + // Token: 0x0600034F RID: 847 RVA: 0x000153EC File Offset: 0x000135EC + public virtual bool IsAddr() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return false; + } + + // Token: 0x06000350 RID: 848 RVA: 0x000153F0 File Offset: 0x000135F0 + public Type GetVariantType() // \u0002 + { + return _type; + } + + // Token: 0x06000351 RID: 849 RVA: 0x000153F8 File Offset: 0x000135F8 + public void SetVariantType(Type val) // \u0002 + { + _type = val; + } + + // Token: 0x04000186 RID: 390 + private Type _type; // \u0002 + + // bug was fixed and unit tested (было превращение Enum в число без учета переполнения) + public static long SignedLongFromEnum(EnumVariant src) + { + var val = src.GetValue(); + switch (Convert.GetTypeCode(val)) + { + /*case TypeCode.SByte: + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.Int64:*/ + default: + return Convert.ToInt64(val); + case TypeCode.Byte: + case TypeCode.UInt16: + case TypeCode.UInt32: + case TypeCode.UInt64: + return (long)Convert.ToUInt64(val); + } + } + + public static VariantBase SignedVariantFromEnum(EnumVariant src) + { + var val = src.GetValue(); + switch (Convert.GetTypeCode(val)) + { + case TypeCode.SByte: + case TypeCode.Int16: + case TypeCode.Int32: + var i = Convert.ToInt32(val); + var reti = new IntVariant(); + reti.SetValue(i); + return reti; + case TypeCode.Int64: + var l = Convert.ToInt64(val); + var retl = new LongVariant(); + retl.SetValue(l); + return retl; + case TypeCode.Byte: + case TypeCode.UInt16: + case TypeCode.UInt32: + var u = Convert.ToUInt32(val); + var retu = new IntVariant(); + retu.SetValue((int)u); + return retu; + //case TypeCode.UInt64: + default: + var ul = Convert.ToUInt64(val); + var retul = new LongVariant(); + retul.SetValue((long)ul); + return retul; + } + } + } + // Token: 0x02000003 RID: 3 + internal sealed class ArrayVariant : VariantBase // \u0002\u2000 + { + // Token: 0x06000009 RID: 9 RVA: 0x000021A8 File Offset: 0x000003A8 + public Array GetValue() // \u0002 + { + return _value; + } + + // Token: 0x0600000A RID: 10 RVA: 0x000021B0 File Offset: 0x000003B0 + public void SetValue(Array val) // \u0002 + { + _value = val; + } + + // Token: 0x0600000B RID: 11 RVA: 0x000021BC File Offset: 0x000003BC + public override object GetValueAbstract() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return GetValue(); + } + + // Token: 0x0600000C RID: 12 RVA: 0x000021C4 File Offset: 0x000003C4 + public override void SetValueAbstract(object o) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetValue((Array)o); + } + + // Token: 0x0600000D RID: 13 RVA: 0x000021D4 File Offset: 0x000003D4 + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new ArrayVariant(); + ret.SetValue(_value); + ret.SetVariantType(GetType()); + return ret; + } + + // Token: 0x0600000E RID: 14 RVA: 0x000021F4 File Offset: 0x000003F4 + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc2Array; + } + + // Token: 0x0600000F RID: 15 RVA: 0x000021F8 File Offset: 0x000003F8 + public override VariantBase CopyFrom(VariantBase src) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(src.GetVariantType()); + var num = src.GetTypeCode(); + if (num != Vtc.Tc2Array) + { + if (num != Vtc.Tc18Object) + { + throw new ArgumentOutOfRangeException(); + } + SetValue((Array)((ObjectVariant)src).GetValue()); + } + else + { + SetValue(((ArrayVariant)src).GetValue()); + } + return this; + } + + // Token: 0x04000001 RID: 1 + private Array _value; // \u0002 + } + + // Token: 0x0200002B RID: 43 + internal sealed class ObjectVariant : VariantBase // \u0006\u2002 + { + // Token: 0x0600013E RID: 318 RVA: 0x00006458 File Offset: 0x00004658 + public object GetValue() // \u0002 + { + return _value; + } + + // Token: 0x0600013F RID: 319 RVA: 0x00006460 File Offset: 0x00004660 + public void SetValue(object val) // \u0002 + { + _value = val; + } + + // Token: 0x06000140 RID: 320 RVA: 0x0000646C File Offset: 0x0000466C + public override object GetValueAbstract() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return GetValue(); + } + + // Token: 0x06000141 RID: 321 RVA: 0x00006474 File Offset: 0x00004674 + public override void SetValueAbstract(object val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetValue(val); + } + + // Token: 0x06000142 RID: 322 RVA: 0x00006480 File Offset: 0x00004680 + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc18Object; + } + + // Token: 0x06000143 RID: 323 RVA: 0x00006484 File Offset: 0x00004684 + public override VariantBase CopyFrom(VariantBase src) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(src.GetVariantType()); + SetValue(src.GetValueAbstract()); + return this; + } + + // Token: 0x06000144 RID: 324 RVA: 0x000064AC File Offset: 0x000046AC + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new ObjectVariant(); + ret.SetValue(_value); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x0400004E RID: 78 + private object _value; + } + + // Token: 0x02000004 RID: 4 + internal sealed class ShortVariant : VariantBase + { + // Token: 0x06000011 RID: 17 RVA: 0x00002260 File Offset: 0x00000460 + public short GetValue() // \u0002 + { + return _value; + } + + // Token: 0x06000012 RID: 18 RVA: 0x00002268 File Offset: 0x00000468 + public void SetValue(short val) // \u0002 + { + _value = val; + } + + // Token: 0x06000013 RID: 19 RVA: 0x00002274 File Offset: 0x00000474 + public override object GetValueAbstract() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return GetValue(); + } + + // Token: 0x06000014 RID: 20 RVA: 0x00002284 File Offset: 0x00000484 + public override void SetValueAbstract(object val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + if (val is int) + { + SetValue((short)(int)val); + return; + } + if (val is long) + { + SetValue((short)(long)val); + return; + } + if (val is ushort) + { + SetValue((short)(ushort)val); + return; + } + if (val is uint) + { + SetValue((short)(uint)val); + return; + } + if (val is ulong) + { + SetValue((short)(ulong)val); + return; + } + if (val is float) + { + SetValue((short)(float)val); + return; + } + if (val is double) + { + SetValue((short)(double)val); + return; + } + SetValue(Convert.ToInt16(val)); + } + + // Token: 0x06000015 RID: 21 RVA: 0x00002338 File Offset: 0x00000538 + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new ShortVariant(); + ret.SetValue(_value); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x06000016 RID: 22 RVA: 0x00002358 File Offset: 0x00000558 + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc15Short; + } + + // Token: 0x06000017 RID: 23 RVA: 0x0000235C File Offset: 0x0000055C + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + switch (val.GetTypeCode()) + { + case Vtc.Tc1Bool: + SetValue(Convert.ToByte(((BoolVariant)val).GetValue())); + return this; + case Vtc.Tc5Enum: + SetValue(Convert.ToInt16(((EnumVariant)val).GetValue())); + return this; + case Vtc.Tc7Ulong: + SetValue((short)((UlongVariant)val).GetValue()); + return this; + case Vtc.Tc8Float: + SetValue((short)((FloatVariant)val).GetValue()); + return this; + case Vtc.Tc9Uint: + SetValue((short)((UintVariant)val).GetValue()); + return this; + case Vtc.Tc10Ushort: + SetValue((short)((UshortVariant)val).GetValue()); + return this; + case Vtc.Tc12Sbyte: + SetValue(((SbyteVariant)val).GetValue()); + return this; + case Vtc.Tc14Byte: + SetValue(((ByteVariant)val).GetValue()); + return this; + case Vtc.Tc15Short: + SetValue(((ShortVariant)val).GetValue()); + return this; + case Vtc.Tc17IntPtr: + SetValue((short)(int)((IntPtrVariant)val).GetValue()); + return this; + case Vtc.Tc18Object: + SetValue(Convert.ToInt16(((ObjectVariant)val).GetValue())); + return this; + case Vtc.Tc19Int: + SetValue((short)((IntVariant)val).GetValue()); + return this; + case Vtc.Tc21Double: + SetValue((short)((DoubleVariant)val).GetValue()); + return this; + case Vtc.Tc24Long: + SetValue((short)((LongVariant)val).GetValue()); + return this; + } + throw new ArgumentOutOfRangeException(); + } + + // Token: 0x04000002 RID: 2 + private short _value; // \u0002 + } + + // Token: 0x02000005 RID: 5 + internal sealed class MethodVariant : VariantBase // \u0002\u2002 + { + // Token: 0x06000019 RID: 25 RVA: 0x00002538 File Offset: 0x00000738 + public MethodBase GetValue() //\u0002 + { + return _value; + } + + // Token: 0x0600001A RID: 26 RVA: 0x00002540 File Offset: 0x00000740 + public void SetValue(MethodBase val) //\u0002 + { + _value = val; + } + + // Token: 0x0600001B RID: 27 RVA: 0x0000254C File Offset: 0x0000074C + public IntPtr GetFunctionPointer() // \u0002 + { + return GetValue().MethodHandle.GetFunctionPointer(); + } + + // Token: 0x0600001C RID: 28 RVA: 0x0000256C File Offset: 0x0000076C + public override object GetValueAbstract() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return GetValue(); + } + + // Token: 0x0600001D RID: 29 RVA: 0x00002574 File Offset: 0x00000774 + public override void SetValueAbstract(object val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetValue((MethodBase)val); + } + + // Token: 0x0600001E RID: 30 RVA: 0x00002584 File Offset: 0x00000784 + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc3Method; + } + + // Token: 0x0600001F RID: 31 RVA: 0x00002588 File Offset: 0x00000788 + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + var num = val.GetTypeCode(); + if (num == Vtc.Tc3Method) + { + SetValue(((MethodVariant)val).GetValue()); + return this; + } + throw new ArgumentOutOfRangeException(); + } + + // Token: 0x06000020 RID: 32 RVA: 0x000025C8 File Offset: 0x000007C8 + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new MethodVariant(); + ret.SetValue(_value); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x04000003 RID: 3 + private MethodBase _value; + } + + // Token: 0x02000008 RID: 8 + internal sealed class StringVariant : VariantBase // \u0002\u2005 + { + // Token: 0x0600002B RID: 43 RVA: 0x000026BC File Offset: 0x000008BC + public string GetValue() // \u0002 + { + return _value; + } + + // Token: 0x0600002C RID: 44 RVA: 0x000026C4 File Offset: 0x000008C4 + public void SetValue(string val) // \u0002 + { + _value = val; + } + + // Token: 0x0600002D RID: 45 RVA: 0x000026D0 File Offset: 0x000008D0 + public override object GetValueAbstract() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return GetValue(); + } + + // Token: 0x0600002E RID: 46 RVA: 0x000026D8 File Offset: 0x000008D8 + public override void SetValueAbstract(object val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetValue((string)val); + } + + // Token: 0x0600002F RID: 47 RVA: 0x000026E8 File Offset: 0x000008E8 + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc16String; + } + + // Token: 0x06000030 RID: 48 RVA: 0x000026EC File Offset: 0x000008EC + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + var num = val.GetTypeCode(); + if (num != Vtc.Tc16String) + { + if (num != Vtc.Tc18Object) + { + throw new ArgumentOutOfRangeException(); + } + SetValue((string)((ObjectVariant)val).GetValue()); + } + else + { + SetValue(((StringVariant)val).GetValue()); + } + return this; + } + + // Token: 0x06000031 RID: 49 RVA: 0x0000274C File Offset: 0x0000094C + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new StringVariant(); + ret.SetValue(_value); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x04000007 RID: 7 + private string _value; + } + + // Token: 0x0200000F RID: 15 + internal sealed class BoolVariant : VariantBase // \u0003\u2000 + { + // Token: 0x06000062 RID: 98 RVA: 0x00003470 File Offset: 0x00001670 + public bool GetValue() // \u0002 + { + return _value; + } + + // Token: 0x06000063 RID: 99 RVA: 0x00003478 File Offset: 0x00001678 + public void SetValue(bool val) // \u0002 + { + _value = val; + } + + // Token: 0x06000064 RID: 100 RVA: 0x00003484 File Offset: 0x00001684 + public override object GetValueAbstract() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return GetValue(); + } + + // Token: 0x06000065 RID: 101 RVA: 0x00003494 File Offset: 0x00001694 + public override void SetValueAbstract(object val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetValue(Convert.ToBoolean(val)); + } + + // Token: 0x06000066 RID: 102 RVA: 0x000034A4 File Offset: 0x000016A4 + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc1Bool; + } + + // Token: 0x06000067 RID: 103 RVA: 0x000034A8 File Offset: 0x000016A8 + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + switch (val.GetTypeCode()) + { + case Vtc.Tc1Bool: + SetValue(((BoolVariant)val).GetValue()); + return this; + case Vtc.Tc5Enum: + SetValue(Convert.ToBoolean(((EnumVariant)val).GetValue())); + return this; + case Vtc.Tc7Ulong: + SetValue(Convert.ToBoolean(((UlongVariant)val).GetValue())); + return this; + case Vtc.Tc9Uint: + SetValue(Convert.ToBoolean(((UintVariant)val).GetValue())); + return this; + case Vtc.Tc10Ushort: + SetValue(Convert.ToBoolean(((UshortVariant)val).GetValue())); + return this; + case Vtc.Tc12Sbyte: + SetValue(Convert.ToBoolean(((SbyteVariant)val).GetValue())); + return this; + case Vtc.Tc13UIntPtr: + SetValue(Convert.ToBoolean(((UIntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc14Byte: + SetValue(Convert.ToBoolean(((ByteVariant)val).GetValue())); + return this; + case Vtc.Tc15Short: + SetValue(Convert.ToBoolean(((ShortVariant)val).GetValue())); + return this; + case Vtc.Tc17IntPtr: + SetValue(Convert.ToBoolean(((IntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc18Object: + SetValue(Convert.ToBoolean(((UIntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc19Int: + SetValue(Convert.ToBoolean(((IntVariant)val).GetValue())); + return this; + case Vtc.Tc24Long: + SetValue(Convert.ToBoolean(((LongVariant)val).GetValue())); + return this; + } + throw new ArgumentOutOfRangeException(); + } + + // Token: 0x06000068 RID: 104 RVA: 0x00003694 File Offset: 0x00001894 + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new BoolVariant(); + ret.SetValue(_value); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x04000017 RID: 23 + private bool _value; + } + + // Token: 0x02000010 RID: 16 + internal sealed class IntVariant : VariantBase // \u0003\u2001 + { + // Token: 0x0600006A RID: 106 RVA: 0x000036BC File Offset: 0x000018BC + public int GetValue() // \u0002 + { + return _value; + } + + // Token: 0x0600006B RID: 107 RVA: 0x000036C4 File Offset: 0x000018C4 + public void SetValue(int val) // \u0002 + { + + _value = val; + } + + // Token: 0x0600006C RID: 108 RVA: 0x000036D0 File Offset: 0x000018D0 + public override object GetValueAbstract() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return GetValue(); + } + + // Token: 0x0600006D RID: 109 RVA: 0x000036E0 File Offset: 0x000018E0 + public override void SetValueAbstract(object val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + if (val is long) + { + SetValue((int)((long)val)); + return; + } + if (val is ushort) + { + SetValue((ushort)val); + return; + } + if (val is uint) + { + SetValue((int)((uint)val)); + return; + } + if (val is ulong) + { + SetValue((int)((ulong)val)); + return; + } + if (val is float) + { + SetValue((int)((float)val)); + return; + } + if (val is double) + { + SetValue((int)((double)val)); + return; + } + SetValue(Convert.ToInt32(val)); + } + + // Token: 0x0600006E RID: 110 RVA: 0x0000377C File Offset: 0x0000197C + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new IntVariant(); + ret.SetValue(_value); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x0600006F RID: 111 RVA: 0x0000379C File Offset: 0x0000199C + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc19Int; + } + + // Token: 0x06000070 RID: 112 RVA: 0x000037A0 File Offset: 0x000019A0 + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + switch (val.GetTypeCode()) + { + case Vtc.Tc1Bool: + SetValue(Convert.ToByte(((BoolVariant)val).GetValue())); + return this; + case Vtc.Tc5Enum: + SetValue(Convert.ToInt32(((EnumVariant)val).GetValue())); + return this; + case Vtc.Tc7Ulong: + SetValue((int)((UlongVariant)val).GetValue()); + return this; + case Vtc.Tc8Float: + SetValue((int)((FloatVariant)val).GetValue()); + return this; + case Vtc.Tc9Uint: + SetValue((int)((UintVariant)val).GetValue()); + return this; + case Vtc.Tc10Ushort: + SetValue(((UshortVariant)val).GetValue()); + return this; + case Vtc.Tc12Sbyte: + SetValue(((SbyteVariant)val).GetValue()); + return this; + case Vtc.Tc13UIntPtr: + SetValue((int)((uint)((UIntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc14Byte: + SetValue(((ByteVariant)val).GetValue()); + return this; + case Vtc.Tc15Short: + SetValue(((ShortVariant)val).GetValue()); + return this; + case Vtc.Tc17IntPtr: + SetValue((int)((IntPtrVariant)val).GetValue()); + return this; + case Vtc.Tc18Object: + SetValue(Convert.ToInt32(((UIntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc19Int: + SetValue(((IntVariant)val).GetValue()); + return this; + case Vtc.Tc21Double: + SetValue((int)((DoubleVariant)val).GetValue()); + return this; + case Vtc.Tc24Long: + SetValue(Convert.ToInt32(((LongVariant)val).GetValue())); + return this; + } + throw new ArgumentOutOfRangeException(); + } + + // Token: 0x04000018 RID: 24 + private int _value; + } + + // Token: 0x02000011 RID: 17 + internal sealed class IntPtrVariant : VariantBase // \u0003\u2002 + { + // Token: 0x06000072 RID: 114 RVA: 0x00003998 File Offset: 0x00001B98 + public IntPtr GetValue() // \u0002 + { + return _value; + } + + // Token: 0x06000073 RID: 115 RVA: 0x000039A0 File Offset: 0x00001BA0 + public void SetValue(IntPtr val) // \u0002 + { + _value = val; + } + + // Token: 0x06000074 RID: 116 RVA: 0x000039AC File Offset: 0x00001BAC + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new IntPtrVariant(); + ret.SetValue(_value); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x06000075 RID: 117 RVA: 0x000039CC File Offset: 0x00001BCC + public override object GetValueAbstract() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return GetValue(); + } + + // Token: 0x06000076 RID: 118 RVA: 0x000039DC File Offset: 0x00001BDC + public override void SetValueAbstract(object val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetValue((IntPtr)val); + } + + // Token: 0x06000077 RID: 119 RVA: 0x000039EC File Offset: 0x00001BEC + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc17IntPtr; + } + + // Token: 0x06000078 RID: 120 RVA: 0x000039F0 File Offset: 0x00001BF0 + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + switch (val.GetTypeCode()) + { + case Vtc.Tc3Method: + { + var mv = (MethodVariant)val; + SetValue(mv.GetFunctionPointer()); + return this; + } + case Vtc.Tc5Enum: + SetValue(new IntPtr(Convert.ToInt64(((EnumVariant)val).GetValue()))); + return this; + case Vtc.Tc7Ulong: + SetValue((IntPtr)((long)((UlongVariant)val).GetValue())); + return this; + case Vtc.Tc8Float: + SetValue((IntPtr)((long)((FloatVariant)val).GetValue())); + return this; + case Vtc.Tc9Uint: + SetValue((IntPtr)((long)((UintVariant)val).GetValue())); + return this; + case Vtc.Tc10Ushort: + SetValue((IntPtr)((int)((UshortVariant)val).GetValue())); + return this; + case Vtc.Tc12Sbyte: + SetValue((IntPtr)((SbyteVariant)val).GetValue()); + return this; + case Vtc.Tc14Byte: + SetValue((IntPtr)((int)((ByteVariant)val).GetValue())); + return this; + case Vtc.Tc15Short: + SetValue((IntPtr)((ShortVariant)val).GetValue()); + return this; + case Vtc.Tc17IntPtr: + SetValue(((IntPtrVariant)val).GetValue()); + return this; + case Vtc.Tc18Object: + SetValue((IntPtr)((UIntPtrVariant)val).GetValue().ToUInt64()); + return this; + case Vtc.Tc19Int: + SetValue((IntPtr)((IntVariant)val).GetValue()); + return this; + case Vtc.Tc21Double: + SetValue((IntPtr)((long)((DoubleVariant)val).GetValue())); + return this; + case Vtc.Tc24Long: + SetValue((IntPtr)((LongVariant)val).GetValue()); + return this; + } + throw new ArgumentOutOfRangeException(); + } + + // Token: 0x04000019 RID: 25 + private IntPtr _value; + } + + // Token: 0x02000014 RID: 20 + internal sealed class ValueTypeVariant : VariantBase // \u0003\u2005 + { + // Token: 0x06000086 RID: 134 RVA: 0x00003CF0 File Offset: 0x00001EF0 + public ValueTypeVariant(object val) + { + if (val != null && !(val is ValueType)) + { + throw new ArgumentException(); + } + _value = val; + } + + // Token: 0x06000087 RID: 135 RVA: 0x00003D10 File Offset: 0x00001F10 + public object GetValue() // \u0002 + { + return _value; + } + + // Token: 0x06000088 RID: 136 RVA: 0x00003D18 File Offset: 0x00001F18 + public void SetValue(object val) // \u0002 + { + if (val != null && !(val is ValueType)) + { + throw new ArgumentException(); + } + _value = val; + } + + // Token: 0x06000089 RID: 137 RVA: 0x00003D34 File Offset: 0x00001F34 + public override object GetValueAbstract() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return GetValue(); + } + + // Token: 0x0600008A RID: 138 RVA: 0x00003D3C File Offset: 0x00001F3C + public override void SetValueAbstract(object val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetValue(val); + } + + // Token: 0x0600008B RID: 139 RVA: 0x00003D48 File Offset: 0x00001F48 + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc11ValueType; + } + + // Token: 0x0600008C RID: 140 RVA: 0x00003D4C File Offset: 0x00001F4C + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + var num = val.GetTypeCode(); + if (num != Vtc.Tc11ValueType) + { + if (num != Vtc.Tc18Object) + { + SetValue(val.GetTypeCode()); + } + else + { + SetValue(((UIntPtrVariant)val).GetValue()); + } + } + else if (GetValue() != null) + { + var obj = ((ValueTypeVariant)val).GetValue(); + var type = GetValue().GetType(); + // ReSharper disable once UseMethodIsInstanceOfType + if (obj != null && !type.IsPrimitive && !type.IsEnum && type.IsAssignableFrom(obj.GetType())) + { + var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.GetField | BindingFlags.SetField); + foreach (var fieldInfo in fields) + { + fieldInfo.SetValue(GetValue(), fieldInfo.GetValue(obj)); + } + } + else + { + SetValue(obj); + } + } + else + { + SetValue(((ValueTypeVariant)val).GetValue()); + } + return this; + } + + // Token: 0x0600008D RID: 141 RVA: 0x00003E38 File Offset: 0x00002038 + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new ValueTypeVariant(_value); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x0400001D RID: 29 + private object _value; + } + + // Token: 0x0200001C RID: 28 + internal sealed class CharVariant : VariantBase // \u0005\u2000 + { + // Token: 0x060000A9 RID: 169 RVA: 0x000042D0 File Offset: 0x000024D0 + public char GetValue() // \u0002 + { + return _value; + } + + // Token: 0x060000AA RID: 170 RVA: 0x000042D8 File Offset: 0x000024D8 + public void SetValue(char val) // \u0002 + { + _value = val; + } + + // Token: 0x060000AB RID: 171 RVA: 0x000042E4 File Offset: 0x000024E4 + public override object GetValueAbstract() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return GetValue(); + } + + // Token: 0x060000AC RID: 172 RVA: 0x000042F4 File Offset: 0x000024F4 + public override void SetValueAbstract(object val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetValue(Convert.ToChar(val)); + } + + // Token: 0x060000AD RID: 173 RVA: 0x00004304 File Offset: 0x00002504 + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc6Char; + } + + // Token: 0x060000AE RID: 174 RVA: 0x00004308 File Offset: 0x00002508 + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + switch (val.GetTypeCode()) + { + case Vtc.Tc1Bool: + SetValue(Convert.ToChar(((BoolVariant)val).GetValue())); + return this; + case Vtc.Tc5Enum: + SetValue(Convert.ToChar(((EnumVariant)val).GetValue())); + return this; + case Vtc.Tc6Char: + SetValue(((CharVariant)val).GetValue()); + return this; + case Vtc.Tc7Ulong: + SetValue((char)((UlongVariant)val).GetValue()); + return this; + case Vtc.Tc9Uint: + SetValue((char)((UintVariant)val).GetValue()); + return this; + case Vtc.Tc10Ushort: + SetValue((char)((UshortVariant)val).GetValue()); + return this; + case Vtc.Tc12Sbyte: + SetValue((char)((SbyteVariant)val).GetValue()); + return this; + case Vtc.Tc13UIntPtr: + SetValue((char)((uint)((UIntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc14Byte: + SetValue((char)((ByteVariant)val).GetValue()); + return this; + case Vtc.Tc15Short: + SetValue((char)((ShortVariant)val).GetValue()); + return this; + case Vtc.Tc17IntPtr: + SetValue((char)((int)((IntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc18Object: + SetValue(Convert.ToChar(((UIntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc19Int: + SetValue((char)((IntVariant)val).GetValue()); + return this; + case Vtc.Tc24Long: + SetValue((char)((LongVariant)val).GetValue()); + return this; + } + throw new ArgumentOutOfRangeException(); + } + + // Token: 0x060000AF RID: 175 RVA: 0x000044E0 File Offset: 0x000026E0 + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new CharVariant(); + ret.SetValue(_value); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x04000026 RID: 38 + private char _value; + } + + // Token: 0x0200001D RID: 29 + internal sealed class LongVariant : VariantBase // \u0005\u2001 + { + // Token: 0x060000B1 RID: 177 RVA: 0x00004508 File Offset: 0x00002708 + public long GetValue() // \u0002 + { + return _value; + } + + // Token: 0x060000B2 RID: 178 RVA: 0x00004510 File Offset: 0x00002710 + public void SetValue(long val) // \u0002 + { + _value = val; + } + + // Token: 0x060000B3 RID: 179 RVA: 0x0000451C File Offset: 0x0000271C + public override object GetValueAbstract() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return GetValue(); + } + + // Token: 0x060000B4 RID: 180 RVA: 0x0000452C File Offset: 0x0000272C + public override void SetValueAbstract(object val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + if (val is ulong) + { + SetValue((long)((ulong)val)); + return; + } + if (val is float) + { + SetValue((long)((float)val)); + return; + } + if (val is double) + { + SetValue((long)((double)val)); + return; + } + SetValue(Convert.ToInt64(val)); + } + + // Token: 0x060000B5 RID: 181 RVA: 0x00004588 File Offset: 0x00002788 + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new LongVariant(); + ret.SetValue(_value); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x060000B6 RID: 182 RVA: 0x000045A8 File Offset: 0x000027A8 + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc24Long; + } + + // Token: 0x060000B7 RID: 183 RVA: 0x000045AC File Offset: 0x000027AC + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + switch (val.GetTypeCode()) + { + case Vtc.Tc1Bool: + SetValue(Convert.ToByte(((BoolVariant)val).GetValue())); + return this; + case Vtc.Tc5Enum: + SetValue(Convert.ToInt64(((EnumVariant)val).GetValue())); + return this; + case Vtc.Tc7Ulong: + SetValue((long)((UlongVariant)val).GetValue()); + return this; + case Vtc.Tc8Float: + SetValue((long)((FloatVariant)val).GetValue()); + return this; + case Vtc.Tc9Uint: + SetValue(((UintVariant)val).GetValue()); + return this; + case Vtc.Tc10Ushort: + SetValue(((UshortVariant)val).GetValue()); + return this; + case Vtc.Tc12Sbyte: + SetValue(((SbyteVariant)val).GetValue()); + return this; + case Vtc.Tc13UIntPtr: + SetValue((long)((ulong)((UIntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc14Byte: + SetValue(((ByteVariant)val).GetValue()); + return this; + case Vtc.Tc15Short: + SetValue(((ShortVariant)val).GetValue()); + return this; + case Vtc.Tc17IntPtr: + SetValue((long)((IntPtrVariant)val).GetValue()); + return this; + case Vtc.Tc18Object: + SetValue(Convert.ToInt64(((UIntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc19Int: + SetValue(((IntVariant)val).GetValue()); + return this; + case Vtc.Tc21Double: + SetValue((long)((DoubleVariant)val).GetValue()); + return this; + case Vtc.Tc24Long: + SetValue(((LongVariant)val).GetValue()); + return this; + } + throw new ArgumentOutOfRangeException(); + } + + // Token: 0x04000027 RID: 39 + private long _value; + } + + // Token: 0x0200001E RID: 30 + internal sealed class UIntPtrVariant : VariantBase // \u0005\u2002 + { + // Token: 0x060000B9 RID: 185 RVA: 0x000047A4 File Offset: 0x000029A4 + public UIntPtr GetValue() // \u0002 + { + return _value; + } + + // Token: 0x060000BA RID: 186 RVA: 0x000047AC File Offset: 0x000029AC + public void SetValue(UIntPtr val) // \u0002 + { + _value = val; + } + + // Token: 0x060000BB RID: 187 RVA: 0x000047B8 File Offset: 0x000029B8 + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new UIntPtrVariant(); + ret.SetValue(_value); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x060000BC RID: 188 RVA: 0x000047D8 File Offset: 0x000029D8 + public override object GetValueAbstract() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return GetValue(); + } + + // Token: 0x060000BD RID: 189 RVA: 0x000047E8 File Offset: 0x000029E8 + public override void SetValueAbstract(object val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetValue((UIntPtr)val); + } + + // Token: 0x060000BE RID: 190 RVA: 0x000047F8 File Offset: 0x000029F8 + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc13UIntPtr; + } + + // Token: 0x060000BF RID: 191 RVA: 0x000047FC File Offset: 0x000029FC + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + switch (val.GetTypeCode()) + { + case Vtc.Tc5Enum: + SetValue(new UIntPtr(Convert.ToUInt64(((EnumVariant)val).GetValue()))); + return this; + case Vtc.Tc7Ulong: + SetValue((UIntPtr)((UlongVariant)val).GetValue()); + return this; + case Vtc.Tc8Float: + SetValue((UIntPtr)((ulong)((FloatVariant)val).GetValue())); + return this; + case Vtc.Tc9Uint: + SetValue((UIntPtr)((UintVariant)val).GetValue()); + return this; + case Vtc.Tc10Ushort: + SetValue((UIntPtr)((UshortVariant)val).GetValue()); + return this; + case Vtc.Tc13UIntPtr: + SetValue(((UIntPtrVariant)val).GetValue()); + return this; + case Vtc.Tc14Byte: + SetValue((UIntPtr)((ByteVariant)val).GetValue()); + return this; + case Vtc.Tc18Object: + SetValue(((UIntPtrVariant)val).GetValue()); + return this; + case Vtc.Tc19Int: + SetValue((UIntPtr)((ulong)((IntVariant)val).GetValue())); + return this; + case Vtc.Tc21Double: + SetValue((UIntPtr)((ulong)((DoubleVariant)val).GetValue())); + return this; + case Vtc.Tc24Long: + SetValue((UIntPtr)((ulong)((LongVariant)val).GetValue())); + return this; + } + throw new ArgumentOutOfRangeException(); + } + + // Token: 0x04000028 RID: 40 + private UIntPtr _value; + } + + // Token: 0x02000029 RID: 41 + internal sealed class DoubleVariant : VariantBase // \u0006\u2000 + { + // Token: 0x0600012E RID: 302 RVA: 0x00005F98 File Offset: 0x00004198 + public double GetValue() + { + return _value; + } + + // Token: 0x0600012F RID: 303 RVA: 0x00005FA0 File Offset: 0x000041A0 + public void SetValue(double val) + { + _value = val; + } + + // Token: 0x06000130 RID: 304 RVA: 0x00005FAC File Offset: 0x000041AC + public override object GetValueAbstract() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return GetValue(); + } + + // Token: 0x06000131 RID: 305 RVA: 0x00005FBC File Offset: 0x000041BC + public override void SetValueAbstract(object val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetValue(Convert.ToDouble(val)); + } + + // Token: 0x06000132 RID: 306 RVA: 0x00005FCC File Offset: 0x000041CC + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new DoubleVariant(); + ret.SetValue(_value); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x06000133 RID: 307 RVA: 0x00005FEC File Offset: 0x000041EC + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc21Double; + } + + // Token: 0x06000134 RID: 308 RVA: 0x00005FF0 File Offset: 0x000041F0 + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + switch (val.GetTypeCode()) + { + case Vtc.Tc7Ulong: + SetValue(((UlongVariant)val).GetValue()); + return this; + case Vtc.Tc8Float: + SetValue(((FloatVariant)val).GetValue()); + return this; + case Vtc.Tc9Uint: + SetValue(((UintVariant)val).GetValue()); + return this; + case Vtc.Tc10Ushort: + SetValue(((UshortVariant)val).GetValue()); + return this; + case Vtc.Tc12Sbyte: + SetValue(((SbyteVariant)val).GetValue()); + return this; + case Vtc.Tc14Byte: + SetValue(((ByteVariant)val).GetValue()); + return this; + case Vtc.Tc15Short: + SetValue(((ShortVariant)val).GetValue()); + return this; + case Vtc.Tc18Object: + SetValue((double)((UIntPtrVariant)val).GetValue()); + return this; + case Vtc.Tc19Int: + SetValue(((IntVariant)val).GetValue()); + return this; + case Vtc.Tc21Double: + SetValue(((DoubleVariant)val).GetValue()); + return this; + case Vtc.Tc24Long: + SetValue(((LongVariant)val).GetValue()); + return this; + } + throw new ArgumentOutOfRangeException(); + } + + // Token: 0x0400004C RID: 76 + private double _value; + } + + // Token: 0x0200002A RID: 42 + internal sealed class UshortVariant : VariantBase // \u0006\u2001 + { + // Token: 0x06000136 RID: 310 RVA: 0x00006164 File Offset: 0x00004364 + public ushort GetValue() // \u0002 + { + return _value; + } + + // Token: 0x06000137 RID: 311 RVA: 0x0000616C File Offset: 0x0000436C + public void SetValue(ushort val) // \u0002 + { + _value = val; + } + + // Token: 0x06000138 RID: 312 RVA: 0x00006178 File Offset: 0x00004378 + public override object GetValueAbstract() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return GetValue(); + } + + // Token: 0x06000139 RID: 313 RVA: 0x00006188 File Offset: 0x00004388 + public override void SetValueAbstract(object val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + if (val is short) + { + SetValue((ushort)((short)val)); + return; + } + if (val is int) + { + SetValue((ushort)((int)val)); + return; + } + if (val is long) + { + SetValue((ushort)((long)val)); + return; + } + if (val is uint) + { + SetValue((ushort)((uint)val)); + return; + } + if (val is ulong) + { + SetValue((ushort)((ulong)val)); + return; + } + if (val is float) + { + SetValue((ushort)((float)val)); + return; + } + if (val is double) + { + SetValue((ushort)((double)val)); + return; + } + SetValue(Convert.ToUInt16(val)); + } + + // Token: 0x0600013A RID: 314 RVA: 0x0000623C File Offset: 0x0000443C + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new UshortVariant(); + ret.SetValue(_value); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x0600013B RID: 315 RVA: 0x0000625C File Offset: 0x0000445C + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc10Ushort; + } + + // Token: 0x0600013C RID: 316 RVA: 0x00006260 File Offset: 0x00004460 + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + switch (val.GetTypeCode()) + { + case Vtc.Tc1Bool: + SetValue(Convert.ToByte(((BoolVariant)val).GetValue())); + return this; + case Vtc.Tc5Enum: + SetValue(Convert.ToUInt16(((EnumVariant)val).GetValue())); + return this; + case Vtc.Tc7Ulong: + SetValue((ushort)((UlongVariant)val).GetValue()); + return this; + case Vtc.Tc8Float: + SetValue((ushort)((FloatVariant)val).GetValue()); + return this; + case Vtc.Tc9Uint: + SetValue((ushort)((UintVariant)val).GetValue()); + return this; + case Vtc.Tc10Ushort: + SetValue(((UshortVariant)val).GetValue()); + return this; + case Vtc.Tc12Sbyte: + SetValue((ushort)((SbyteVariant)val).GetValue()); + return this; + case Vtc.Tc13UIntPtr: + SetValue((ushort)((uint)((UIntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc14Byte: + SetValue(((ByteVariant)val).GetValue()); + return this; + case Vtc.Tc15Short: + SetValue((ushort)((ShortVariant)val).GetValue()); + return this; + case Vtc.Tc17IntPtr: + SetValue((ushort)((int)((IntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc18Object: + SetValue(Convert.ToUInt16(((UIntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc19Int: + SetValue((ushort)((IntVariant)val).GetValue()); + return this; + case Vtc.Tc21Double: + SetValue((ushort)((DoubleVariant)val).GetValue()); + return this; + case Vtc.Tc24Long: + SetValue((ushort)((LongVariant)val).GetValue()); + return this; + } + throw new ArgumentOutOfRangeException(); + } + + // Token: 0x0400004D RID: 77 + private ushort _value; + } + + // Token: 0x02000043 RID: 67 + internal sealed class EnumVariant : VariantBase // \u0008\u2000 + { + // Token: 0x060002E6 RID: 742 RVA: 0x00013F1C File Offset: 0x0001211C + public EnumVariant(Enum val) + { + if (val == null) + { + throw new ArgumentException(); + } + _value = val; + } + + // Token: 0x060002E7 RID: 743 RVA: 0x00013F34 File Offset: 0x00012134 + public Enum GetValue() // \u0002 + { + return _value; + } + + // Token: 0x060002E8 RID: 744 RVA: 0x00013F3C File Offset: 0x0001213C + public void SetValue(Enum val) // \u0002 + { + if (val == null) + { + throw new ArgumentException(); + } + _value = val; + } + + // Token: 0x060002E9 RID: 745 RVA: 0x00013F50 File Offset: 0x00012150 + public override object GetValueAbstract() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return GetValue(); + } + + // Token: 0x060002EA RID: 746 RVA: 0x00013F58 File Offset: 0x00012158 + public override void SetValueAbstract(object val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetValue((Enum)Enum.Parse(GetValue().GetType(), val.ToString())); + } + + // Token: 0x060002EB RID: 747 RVA: 0x00013F88 File Offset: 0x00012188 + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc5Enum; + } + + // Token: 0x060002EC RID: 748 RVA: 0x00013F8C File Offset: 0x0001218C + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + var num = val.GetTypeCode(); + switch (num) + { + case Vtc.Tc5Enum: + { + var type = _value.GetType(); + var @enum = ((EnumVariant)val).GetValue(); + if (@enum.GetType() == type) + { + SetValue(@enum); + return this; + } + SetValue((Enum)Enum.ToObject(type, @enum)); + return this; + } + case Vtc.Tc6Char: + case Vtc.Tc8Float: + case Vtc.Tc11ValueType: + case Vtc.Tc13UIntPtr: + case Vtc.Tc16String: + case Vtc.Tc17IntPtr: + break; + case Vtc.Tc7Ulong: + SetValue((Enum)Enum.ToObject(_value.GetType(), ((UlongVariant)val).GetValue())); + return this; + case Vtc.Tc9Uint: + SetValue((Enum)Enum.ToObject(_value.GetType(), ((UintVariant)val).GetValue())); + return this; + case Vtc.Tc10Ushort: + SetValue((Enum)Enum.ToObject(_value.GetType(), ((UshortVariant)val).GetValue())); + return this; + case Vtc.Tc12Sbyte: + SetValue((Enum)Enum.ToObject(_value.GetType(), ((SbyteVariant)val).GetValue())); + return this; + case Vtc.Tc14Byte: + SetValue((Enum)Enum.ToObject(_value.GetType(), ((ByteVariant)val).GetValue())); + return this; + case Vtc.Tc15Short: + SetValue((Enum)Enum.ToObject(_value.GetType(), ((ShortVariant)val).GetValue())); + return this; + case Vtc.Tc18Object: + SetValue((Enum)Enum.ToObject(_value.GetType(), ((UIntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc19Int: + SetValue((Enum)Enum.ToObject(_value.GetType(), ((IntVariant)val).GetValue())); + return this; + default: + if (num == Vtc.Tc24Long) + { + SetValue((Enum)Enum.ToObject(_value.GetType(), ((LongVariant)val).GetValue())); + return this; + } + break; + } + throw new ArgumentOutOfRangeException(); + } + + // Token: 0x060002ED RID: 749 RVA: 0x000141C0 File Offset: 0x000123C0 + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new EnumVariant(_value); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x04000172 RID: 370 + private Enum _value; + } + + // Token: 0x02000044 RID: 68 + internal sealed class SbyteVariant : VariantBase // \u0008\u2001 + { + // Token: 0x060002EF RID: 751 RVA: 0x000141E4 File Offset: 0x000123E4 + public sbyte GetValue() // \u0002 + { + return _value; + } + + // Token: 0x060002F0 RID: 752 RVA: 0x000141EC File Offset: 0x000123EC + public void SetValue(sbyte val) // \u0002 + { + _value = val; + } + + // Token: 0x060002F1 RID: 753 RVA: 0x000141F8 File Offset: 0x000123F8 + public override object GetValueAbstract() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return GetValue(); + } + + // Token: 0x060002F2 RID: 754 RVA: 0x00014208 File Offset: 0x00012408 + public override void SetValueAbstract(object val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + if (val is byte) + { + SetValue((sbyte)((byte)val)); + return; + } + if (val is short) + { + SetValue((sbyte)((short)val)); + return; + } + if (val is int) + { + SetValue((sbyte)((int)val)); + return; + } + if (val is long) + { + SetValue((sbyte)((long)val)); + return; + } + if (val is ushort) + { + SetValue((sbyte)((ushort)val)); + return; + } + if (val is uint) + { + SetValue((sbyte)((uint)val)); + return; + } + if (val is ulong) + { + SetValue((sbyte)((ulong)val)); + return; + } + if (val is float) + { + SetValue((sbyte)((float)val)); + return; + } + if (val is double) + { + SetValue((sbyte)((double)val)); + return; + } + SetValue(Convert.ToSByte(val)); + } + + // Token: 0x060002F3 RID: 755 RVA: 0x000142E8 File Offset: 0x000124E8 + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new SbyteVariant(); + ret.SetValue(_value); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x060002F4 RID: 756 RVA: 0x00014308 File Offset: 0x00012508 + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc12Sbyte; + } + + // Token: 0x060002F5 RID: 757 RVA: 0x0001430C File Offset: 0x0001250C + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + switch (val.GetTypeCode()) + { + case Vtc.Tc1Bool: + SetValue(Convert.ToSByte(((BoolVariant)val).GetValue())); + return this; + case Vtc.Tc5Enum: + SetValue(Convert.ToSByte(((EnumVariant)val).GetValue())); + return this; + case Vtc.Tc7Ulong: + SetValue((sbyte)((UlongVariant)val).GetValue()); + return this; + case Vtc.Tc8Float: + SetValue((sbyte)((FloatVariant)val).GetValue()); + return this; + case Vtc.Tc9Uint: + SetValue((sbyte)((UintVariant)val).GetValue()); + return this; + case Vtc.Tc10Ushort: + SetValue((sbyte)((UshortVariant)val).GetValue()); + return this; + case Vtc.Tc12Sbyte: + SetValue(((SbyteVariant)val).GetValue()); + return this; + case Vtc.Tc14Byte: + SetValue((sbyte)((ByteVariant)val).GetValue()); + return this; + case Vtc.Tc15Short: + SetValue((sbyte)((ShortVariant)val).GetValue()); + return this; + case Vtc.Tc17IntPtr: + SetValue((sbyte)((int)((IntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc18Object: + SetValue(Convert.ToSByte(((UIntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc19Int: + SetValue((sbyte)((IntVariant)val).GetValue()); + return this; + case Vtc.Tc21Double: + SetValue((sbyte)((DoubleVariant)val).GetValue()); + return this; + case Vtc.Tc24Long: + SetValue((sbyte)((LongVariant)val).GetValue()); + return this; + } + throw new ArgumentOutOfRangeException(); + } + + // Token: 0x04000173 RID: 371 + private sbyte _value; + } + + // Token: 0x0200004E RID: 78 + internal sealed class FloatVariant : VariantBase // \u000E\u2000 + { + // Token: 0x06000326 RID: 806 RVA: 0x00014CA4 File Offset: 0x00012EA4 + public float GetValue() // \u0002 + { + return _value; + } + + // Token: 0x06000327 RID: 807 RVA: 0x00014CAC File Offset: 0x00012EAC + public void SetValue(float val) // \u0002 + { + _value = val; + } + + // Token: 0x06000328 RID: 808 RVA: 0x00014CB8 File Offset: 0x00012EB8 + public override object GetValueAbstract() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return GetValue(); + } + + // Token: 0x06000329 RID: 809 RVA: 0x00014CC8 File Offset: 0x00012EC8 + public override void SetValueAbstract(object val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetValue(Convert.ToSingle(val)); + } + + // Token: 0x0600032A RID: 810 RVA: 0x00014CD8 File Offset: 0x00012ED8 + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new FloatVariant(); + ret.SetValue(_value); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x0600032B RID: 811 RVA: 0x00014CF8 File Offset: 0x00012EF8 + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc8Float; + } + + // Token: 0x0600032C RID: 812 RVA: 0x00014CFC File Offset: 0x00012EFC + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + switch (val.GetTypeCode()) + { + case Vtc.Tc5Enum: + SetValue(Convert.ToSingle(((EnumVariant)val).GetValue())); + return this; + case Vtc.Tc7Ulong: + SetValue(((UlongVariant)val).GetValue()); + return this; + case Vtc.Tc8Float: + SetValue(((FloatVariant)val).GetValue()); + return this; + case Vtc.Tc9Uint: + SetValue(((UintVariant)val).GetValue()); + return this; + case Vtc.Tc10Ushort: + SetValue(((UshortVariant)val).GetValue()); + return this; + case Vtc.Tc12Sbyte: + SetValue(((SbyteVariant)val).GetValue()); + return this; + case Vtc.Tc14Byte: + SetValue(((ByteVariant)val).GetValue()); + return this; + case Vtc.Tc15Short: + SetValue(((ShortVariant)val).GetValue()); + return this; + case Vtc.Tc18Object: + SetValue((float)((UIntPtrVariant)val).GetValue()); + return this; + case Vtc.Tc19Int: + SetValue(((IntVariant)val).GetValue()); + return this; + case Vtc.Tc21Double: + SetValue((float)((DoubleVariant)val).GetValue()); + return this; + case Vtc.Tc24Long: + SetValue(((LongVariant)val).GetValue()); + return this; + } + throw new ArgumentOutOfRangeException(); + } + + // Token: 0x0400017E RID: 382 + private float _value; + } + + // Token: 0x0200004F RID: 79 + internal sealed class UintVariant : VariantBase // \u000E\u2001 + { + // Token: 0x0600032E RID: 814 RVA: 0x00014E94 File Offset: 0x00013094 + public uint GetValue() // \u0002 + { + return _value; + } + + // Token: 0x0600032F RID: 815 RVA: 0x00014E9C File Offset: 0x0001309C + public void SetValue(uint val) // \u0002 + { + _value = val; + } + + // Token: 0x06000330 RID: 816 RVA: 0x00014EA8 File Offset: 0x000130A8 + public override object GetValueAbstract() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return GetValue(); + } + + // Token: 0x06000331 RID: 817 RVA: 0x00014EB8 File Offset: 0x000130B8 + public override void SetValueAbstract(object val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + if (val is short) + { + SetValue((uint)((short)val)); + return; + } + if (val is int) + { + SetValue((uint)((int)val)); + return; + } + if (val is long) + { + SetValue((uint)((long)val)); + return; + } + if (val is ulong) + { + SetValue((uint)((ulong)val)); + return; + } + if (val is float) + { + SetValue((uint)((float)val)); + return; + } + if (val is double) + { + SetValue((uint)((double)val)); + return; + } + SetValue(Convert.ToUInt32(val)); + } + + // Token: 0x06000332 RID: 818 RVA: 0x00014F54 File Offset: 0x00013154 + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new UintVariant(); + ret.SetValue(_value); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x06000333 RID: 819 RVA: 0x00014F74 File Offset: 0x00013174 + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc9Uint; + } + + // Token: 0x06000334 RID: 820 RVA: 0x00014F78 File Offset: 0x00013178 + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + switch (val.GetTypeCode()) + { + case Vtc.Tc1Bool: + SetValue(Convert.ToByte(((BoolVariant)val).GetValue())); + return this; + case Vtc.Tc5Enum: + SetValue(Convert.ToUInt32(((EnumVariant)val).GetValue())); + return this; + case Vtc.Tc7Ulong: + SetValue((uint)((UlongVariant)val).GetValue()); + return this; + case Vtc.Tc8Float: + SetValue((uint)((FloatVariant)val).GetValue()); + return this; + case Vtc.Tc9Uint: + SetValue(((UintVariant)val).GetValue()); + return this; + case Vtc.Tc10Ushort: + SetValue(((UshortVariant)val).GetValue()); + return this; + case Vtc.Tc12Sbyte: + SetValue((uint)((SbyteVariant)val).GetValue()); + return this; + case Vtc.Tc13UIntPtr: + SetValue((uint)((UIntPtrVariant)val).GetValue()); + return this; + case Vtc.Tc14Byte: + SetValue(((ByteVariant)val).GetValue()); + return this; + case Vtc.Tc15Short: + SetValue((uint)((ShortVariant)val).GetValue()); + return this; + case Vtc.Tc17IntPtr: + SetValue((uint)((int)((IntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc18Object: + SetValue(Convert.ToUInt32(((UIntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc19Int: + SetValue((uint)((IntVariant)val).GetValue()); + return this; + case Vtc.Tc21Double: + SetValue((uint)((DoubleVariant)val).GetValue()); + return this; + case Vtc.Tc24Long: + SetValue((uint)((LongVariant)val).GetValue()); + return this; + } + throw new ArgumentOutOfRangeException(); + } + + // Token: 0x0400017F RID: 383 + private uint _value; + } + + // Token: 0x0200005A RID: 90 + internal sealed class ByteVariant : VariantBase // \u000F\u2000 + { + // Token: 0x06000353 RID: 851 RVA: 0x0001540C File Offset: 0x0001360C + public byte GetValue() // \u0002 + { + return _value; + } + + // Token: 0x06000354 RID: 852 RVA: 0x00015414 File Offset: 0x00013614 + public void SetValue(byte val) // \u0002 + { + _value = val; + } + + // Token: 0x06000355 RID: 853 RVA: 0x00015420 File Offset: 0x00013620 + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new ByteVariant(); + ret.SetValue(_value); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x06000356 RID: 854 RVA: 0x00015440 File Offset: 0x00013640 + public override object GetValueAbstract() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return GetValue(); + } + + // Token: 0x06000357 RID: 855 RVA: 0x00015450 File Offset: 0x00013650 + public override void SetValueAbstract(object val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + if (val is short) + { + SetValue((byte)((short)val)); + return; + } + if (val is int) + { + SetValue((byte)((int)val)); + return; + } + if (val is long) + { + SetValue((byte)((long)val)); + return; + } + if (val is ushort) + { + SetValue((byte)((ushort)val)); + return; + } + if (val is uint) + { + SetValue((byte)((uint)val)); + return; + } + if (val is ulong) + { + SetValue((byte)((ulong)val)); + return; + } + if (val is float) + { + SetValue((byte)((float)val)); + return; + } + if (val is double) + { + SetValue((byte)((double)val)); + return; + } + SetValue(Convert.ToByte(val)); + } + + // Token: 0x06000358 RID: 856 RVA: 0x0001551C File Offset: 0x0001371C + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc14Byte; + } + + // Token: 0x06000359 RID: 857 RVA: 0x00015520 File Offset: 0x00013720 + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + switch (val.GetTypeCode()) + { + case Vtc.Tc1Bool: + SetValue(Convert.ToByte(((BoolVariant)val).GetValue())); + return this; + case Vtc.Tc5Enum: + SetValue(Convert.ToByte(((EnumVariant)val).GetValue())); + return this; + case Vtc.Tc7Ulong: + SetValue((byte)((UlongVariant)val).GetValue()); + return this; + case Vtc.Tc8Float: + SetValue((byte)((FloatVariant)val).GetValue()); + return this; + case Vtc.Tc9Uint: + SetValue((byte)((UintVariant)val).GetValue()); + return this; + case Vtc.Tc10Ushort: + SetValue((byte)((UshortVariant)val).GetValue()); + return this; + case Vtc.Tc12Sbyte: + SetValue((byte)((SbyteVariant)val).GetValue()); + return this; + case Vtc.Tc13UIntPtr: + SetValue((byte)((uint)((UIntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc14Byte: + SetValue(((ByteVariant)val).GetValue()); + return this; + case Vtc.Tc15Short: + SetValue((byte)((ShortVariant)val).GetValue()); + return this; + case Vtc.Tc17IntPtr: + SetValue((byte)((int)((IntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc18Object: + SetValue(Convert.ToByte(((UIntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc19Int: + SetValue((byte)((IntVariant)val).GetValue()); + return this; + case Vtc.Tc21Double: + SetValue((byte)((DoubleVariant)val).GetValue()); + return this; + case Vtc.Tc24Long: + SetValue((byte)((LongVariant)val).GetValue()); + return this; + } + throw new ArgumentOutOfRangeException(); + } + + // Token: 0x04000187 RID: 391 + private byte _value; + } + + // Token: 0x0200005B RID: 91 + internal sealed class UlongVariant : VariantBase // \u000F\u2001 + { + // Token: 0x0600035B RID: 859 RVA: 0x00015718 File Offset: 0x00013918 + public ulong GetValue() // \u0002 + { + return _value; + } + + // Token: 0x0600035C RID: 860 RVA: 0x00015720 File Offset: 0x00013920 + public void SetValue(ulong val) // \u0002 + { + _value = val; + } + + // Token: 0x0600035D RID: 861 RVA: 0x0001572C File Offset: 0x0001392C + public override object GetValueAbstract() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return GetValue(); + } + + // Token: 0x0600035E RID: 862 RVA: 0x0001573C File Offset: 0x0001393C + public override void SetValueAbstract(object val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + if (val is short) + { + SetValue((ulong)(short)val); + return; + } + if (val is int) + { + SetValue((ulong)(int)val); + return; + } + if (val is long) + { + SetValue((ulong)((long)val)); + return; + } + if (val is float) + { + SetValue((ulong)((float)val)); + return; + } + if (val is double) + { + SetValue((ulong)((double)val)); + return; + } + SetValue(Convert.ToUInt64(val)); + } + + // Token: 0x0600035F RID: 863 RVA: 0x000157C4 File Offset: 0x000139C4 + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new UlongVariant(); + ret.SetValue(_value); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x06000360 RID: 864 RVA: 0x000157E4 File Offset: 0x000139E4 + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc7Ulong; + } + + // Token: 0x06000361 RID: 865 RVA: 0x000157E8 File Offset: 0x000139E8 + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + switch (val.GetTypeCode()) + { + case Vtc.Tc1Bool: + SetValue(Convert.ToByte(((BoolVariant)val).GetValue())); + return this; + case Vtc.Tc5Enum: + SetValue(Convert.ToUInt64(((EnumVariant)val).GetValue())); + return this; + case Vtc.Tc7Ulong: + SetValue(((UlongVariant)val).GetValue()); + return this; + case Vtc.Tc8Float: + SetValue((ulong)((FloatVariant)val).GetValue()); + return this; + case Vtc.Tc9Uint: + SetValue(((UintVariant)val).GetValue()); + return this; + case Vtc.Tc10Ushort: + SetValue(((UshortVariant)val).GetValue()); + return this; + case Vtc.Tc12Sbyte: + SetValue((ulong)((SbyteVariant)val).GetValue()); + return this; + case Vtc.Tc13UIntPtr: + SetValue((ulong)((UIntPtrVariant)val).GetValue()); + return this; + case Vtc.Tc14Byte: + SetValue(((ByteVariant)val).GetValue()); + return this; + case Vtc.Tc15Short: + SetValue((ulong)((ShortVariant)val).GetValue()); + return this; + case Vtc.Tc17IntPtr: + SetValue((ulong)((long)((IntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc18Object: + SetValue(Convert.ToUInt64(((UIntPtrVariant)val).GetValue())); + return this; + case Vtc.Tc19Int: + SetValue((ulong)((IntVariant)val).GetValue()); + return this; + case Vtc.Tc21Double: + SetValue((ulong)((DoubleVariant)val).GetValue()); + return this; + case Vtc.Tc24Long: + SetValue((ulong)((LongVariant)val).GetValue()); + return this; + } + throw new ArgumentOutOfRangeException(); + } + + // Token: 0x04000188 RID: 392 + private ulong _value; + } + + // Token: 0x0200005C RID: 92 + internal abstract class ReferenceVariantBase : VariantBase // \u000F\u2002 + { + // Token: 0x06000363 RID: 867 RVA: 0x000159E0 File Offset: 0x00013BE0 + public override object GetValueAbstract() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + throw new InvalidOperationException(); + } + + // Token: 0x06000364 RID: 868 RVA: 0x000159E8 File Offset: 0x00013BE8 + public override void SetValueAbstract(object val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + throw new InvalidOperationException(); + } + + // Token: 0x06000365 RID: 869 RVA: 0x000159F0 File Offset: 0x00013BF0 + public override bool IsAddr() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return true; + } + } + + // Token: 0x02000007 RID: 7 + internal sealed class FieldInfoVariant : ReferenceVariantBase // \u0002\u2004 + { + // Token: 0x06000023 RID: 35 RVA: 0x00002600 File Offset: 0x00000800 + public object GetObject() // \u0002 + { + return _obj; + } + + // Token: 0x06000024 RID: 36 RVA: 0x00002608 File Offset: 0x00000808 + public void SetObject(object val) // \u0002 + { + _obj = val; + } + + // Token: 0x06000025 RID: 37 RVA: 0x00002614 File Offset: 0x00000814 + public FieldInfo GetValue() // \u0002 + { + return _field; + } + + // Token: 0x06000026 RID: 38 RVA: 0x0000261C File Offset: 0x0000081C + public void SetValue(FieldInfo val) // \u0002 + { + _field = val; + } + + // Token: 0x06000027 RID: 39 RVA: 0x00002628 File Offset: 0x00000828 + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc4FieldInfo; + } + + // Token: 0x06000028 RID: 40 RVA: 0x0000262C File Offset: 0x0000082C + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + var num = val.GetTypeCode(); + if (num == Vtc.Tc4FieldInfo) + { + SetObject(((FieldInfoVariant)val).GetObject()); + SetValue(((FieldInfoVariant)val).GetValue()); + return this; + } + throw new ArgumentOutOfRangeException(); + } + + // Token: 0x06000029 RID: 41 RVA: 0x0000267C File Offset: 0x0000087C + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new FieldInfoVariant(); + ret.SetObject(_obj); + ret.SetValue(_field); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x04000005 RID: 5 + private object _obj; // \u0002 + + // Token: 0x04000006 RID: 6 + private FieldInfo _field; // \u0003 + } + + // Token: 0x02000012 RID: 18 + internal sealed class VariantBaseHolder : ReferenceVariantBase // \u0003\u2003 + { + // Token: 0x0600007A RID: 122 RVA: 0x00003BF0 File Offset: 0x00001DF0 + public VariantBase GetValue() // \u0002 + { + return _value; + } + + // Token: 0x0600007B RID: 123 RVA: 0x00003BF8 File Offset: 0x00001DF8 + public void SetValue(VariantBase val) // \u0002 + { + _value = val; + } + + // Token: 0x0600007C RID: 124 RVA: 0x00003C04 File Offset: 0x00001E04 + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc0VariantBaseHolder; + } + + // Token: 0x0600007D RID: 125 RVA: 0x00003C08 File Offset: 0x00001E08 + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + if (val.GetTypeCode() == Vtc.Tc0VariantBaseHolder) + { + SetValue(((VariantBaseHolder)val).GetValue()); + return this; + } + throw new ArgumentOutOfRangeException(); + } + + // Token: 0x0600007E RID: 126 RVA: 0x00003C48 File Offset: 0x00001E48 + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new VariantBaseHolder(); + ret.SetValue(GetValue()); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x0400001A RID: 26 + private VariantBase _value; + } + + // Token: 0x02000020 RID: 32 + internal sealed class LocalsIdxHolderVariant : ReferenceVariantBase // \u0005\u2004 + { + // Token: 0x060000C6 RID: 198 RVA: 0x000049A8 File Offset: 0x00002BA8 + public int GetValue() // \u0002 + { + return _value; + } + + // Token: 0x060000C7 RID: 199 RVA: 0x000049B0 File Offset: 0x00002BB0 + public void SetValue(int val) // \u0002 + { + _value = val; + } + + // Token: 0x060000C8 RID: 200 RVA: 0x000049BC File Offset: 0x00002BBC + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc23LocalsIdxHolder; + } + + // Token: 0x060000C9 RID: 201 RVA: 0x000049C0 File Offset: 0x00002BC0 + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + var num = val.GetTypeCode(); + if (num == Vtc.Tc23LocalsIdxHolder) + { + SetValue(((LocalsIdxHolderVariant)val).GetValue()); + return this; + } + throw new ArgumentOutOfRangeException(); + } + + // Token: 0x060000CA RID: 202 RVA: 0x00004A00 File Offset: 0x00002C00 + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new LocalsIdxHolderVariant(); + ret.SetValue(_value); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x04000029 RID: 41 + private int _value; + } + + // Token: 0x02000046 RID: 70 + internal abstract class ArrayValueVariantBase : ReferenceVariantBase // \u0008\u2003 + { + // Token: 0x060002F9 RID: 761 RVA: 0x00014788 File Offset: 0x00012988 + public Type GetHeldType() // \u0002 + { + return _type; + } + + // Token: 0x060002FA RID: 762 RVA: 0x00014790 File Offset: 0x00012990 + public void SetHeldType(Type val) // \u0002 + { + _type = val; + } + + // Token: 0x060002FB RID: 763 + public abstract object GetValue(); // \u0008\u2003\u2008\u2000\u2002\u200A\u0002 + + // Token: 0x060002FC RID: 764 + public abstract void SetValue(object val); // \u0008\u2003\u2008\u2000\u2002\u200A\u0002 + + // Token: 0x060002FD RID: 765 + public abstract bool IsEqual(ArrayValueVariantBase val); // \u0008\u2003\u2008\u2000\u2002\u200A\u0002 + + // Token: 0x04000174 RID: 372 + private Type _type; + } + + // Token: 0x02000053 RID: 83 + internal static class IntArrayComparison // \u000E\u2004 + { + // Token: 0x06000340 RID: 832 RVA: 0x00015294 File Offset: 0x00013494 + public static bool Execute(int[] a1, int[] a2) // \u0002 + { + if (a1 == a2) + { + return true; + } + if (a1 == null || a2 == null) + { + return false; + } + if (a1.Length != a2.Length) + { + return false; + } + return !a1.Where((t, i) => t != a2[i]).Any(); + } + } + + // Token: 0x0200002D RID: 45 + internal sealed class MdArrayValueVariant : ArrayValueVariantBase // \u0006\u2004 + { + // Token: 0x0600014F RID: 335 RVA: 0x000065AC File Offset: 0x000047AC + public Array GetArray() // \u0002 + { + return _array; + } + + // Token: 0x06000150 RID: 336 RVA: 0x000065B4 File Offset: 0x000047B4 + public void SetArray(Array val) // \u0002 + { + _array = val; + } + + // Token: 0x06000151 RID: 337 RVA: 0x000065C0 File Offset: 0x000047C0 + public int[] GetIndexes() // \u0002 + { + return _indexes; + } + + // Token: 0x06000152 RID: 338 RVA: 0x000065C8 File Offset: 0x000047C8 + public void SetIndexes(int[] val) // \u0002 + { + _indexes = val; + } + + // Token: 0x06000153 RID: 339 RVA: 0x000065D4 File Offset: 0x000047D4 + public override object GetValue() // \u0008\u2003\u2008\u2000\u2002\u200A\u0002 + { + return GetArray().GetValue(GetIndexes()); + } + + // Token: 0x06000154 RID: 340 RVA: 0x000065E8 File Offset: 0x000047E8 + public override void SetValue(object val) // \u0008\u2003\u2008\u2000\u2002\u200A\u0002 + { + GetArray().SetValue(val, GetIndexes()); + } + + // Token: 0x06000155 RID: 341 RVA: 0x000065FC File Offset: 0x000047FC + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new MdArrayValueVariant(); + ret.SetArray(GetArray()); + ret.SetIndexes(GetIndexes()); + ret.SetHeldType(GetHeldType()); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x06000156 RID: 342 RVA: 0x00006640 File Offset: 0x00004840 + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc20MdArrayValue; + } + + // Token: 0x06000157 RID: 343 RVA: 0x00006644 File Offset: 0x00004844 + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + var num = val.GetTypeCode(); + if (num == Vtc.Tc20MdArrayValue) + { + var src = (MdArrayValueVariant)val; + SetArray(src.GetArray()); + SetIndexes(src.GetIndexes()); + SetHeldType(src.GetHeldType()); + return this; + } + throw new ArgumentOutOfRangeException(); + } + + // Token: 0x06000158 RID: 344 RVA: 0x000066A0 File Offset: 0x000048A0 + public override bool IsEqual(ArrayValueVariantBase val) // \u0008\u2003\u2008\u2000\u2002\u200A\u0002 + { + var peer = (MdArrayValueVariant)val; + return GetArray() == peer.GetArray() && IntArrayComparison.Execute(GetIndexes(), peer.GetIndexes()); + } + + // Token: 0x04000050 RID: 80 + private Array _array; // \u0002 + + // Token: 0x04000051 RID: 81 + private int[] _indexes; // \u0003 + } + + // Token: 0x02000052 RID: 82 + internal sealed class SdArrayValueVariant : ArrayValueVariantBase // \u000E\u2003 + { + // Token: 0x06000336 RID: 822 RVA: 0x0001516C File Offset: 0x0001336C + public Array GetArray() // \u0002 + { + return _array; + } + + // Token: 0x06000337 RID: 823 RVA: 0x00015174 File Offset: 0x00013374 + public void SetArray(Array val) // \u0002 + { + _array = val; + } + + // Token: 0x06000338 RID: 824 RVA: 0x00015180 File Offset: 0x00013380 + public long GetIndex() // \u0002 + { + return _index; + } + + // Token: 0x06000339 RID: 825 RVA: 0x00015188 File Offset: 0x00013388 + public void SetIndex(long idx) // \u0002 + { + _index = idx; + } + + // Token: 0x0600033A RID: 826 RVA: 0x00015194 File Offset: 0x00013394 + public override object GetValue() // \u0008\u2003\u2008\u2000\u2002\u200A\u0002 + { + return _array.GetValue(_index); + } + + // Token: 0x0600033B RID: 827 RVA: 0x000151A8 File Offset: 0x000133A8 + public override void SetValue(object val) // \u0008\u2003\u2008\u2000\u2002\u200A\u0002 + { + _array.SetValue(val, _index); + } + + // Token: 0x0600033C RID: 828 RVA: 0x000151BC File Offset: 0x000133BC + public override Vtc GetTypeCode() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + return Vtc.Tc22SdArrayValue; + } + + // Token: 0x0600033D RID: 829 RVA: 0x000151C0 File Offset: 0x000133C0 + public override VariantBase CopyFrom(VariantBase val) // \u000F\u2008\u2000\u2002\u200A\u0002 + { + SetVariantType(val.GetVariantType()); + var num = val.GetTypeCode(); + if (num == Vtc.Tc22SdArrayValue) + { + var src = (SdArrayValueVariant)val; + SetArray(src.GetArray()); + SetIndex(src.GetIndex()); + SetHeldType(src.GetHeldType()); + return this; + } + throw new ArgumentOutOfRangeException(); + } + + // Token: 0x0600033E RID: 830 RVA: 0x0001521C File Offset: 0x0001341C + public override VariantBase Clone() // \u000F\u2008\u2000\u2002\u200A\u0002 + { + var ret = new SdArrayValueVariant(); + ret.SetArray(_array); + ret.SetIndex(_index); + ret.SetHeldType(GetHeldType()); + ret.SetVariantType(GetVariantType()); + return ret; + } + + // Token: 0x0600033F RID: 831 RVA: 0x00015260 File Offset: 0x00013460 + public override bool IsEqual(ArrayValueVariantBase val) // \u0008\u2003\u2008\u2000\u2002\u200A\u0002 + { + var peer = (SdArrayValueVariant)val; + return GetIndex() == peer.GetIndex() && GetArray() == peer.GetArray(); + } + + // Token: 0x04000181 RID: 385 + private Array _array; // \u0002 + + // Token: 0x04000182 RID: 386 + private long _index; // \u0003 + } +} diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VariantFactory.cs b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VariantFactory.cs new file mode 100644 index 0000000..c43bbd4 --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VariantFactory.cs @@ -0,0 +1,165 @@ +using System; +using System.Runtime.Serialization; + +namespace UnitTestProject.RefVm +{ + // Token: 0x02000045 RID: 69 + internal static class VariantFactory // \u0008\u2002 + { + // Token: 0x060002F6 RID: 758 RVA: 0x000144E0 File Offset: 0x000126E0 + private static bool IsDerivedFrom<T>(Type obj) // \u0002 + { + var typeFromHandle = typeof(T); + return obj == typeFromHandle || obj.IsSubclassOf(typeFromHandle); + } + + // Token: 0x060002F7 RID: 759 RVA: 0x00014508 File Offset: 0x00012708 + public static VariantBase Convert(object src, Type t) // \u0002 + { + var ret = src as VariantBase; + if (ret != null) + { + return ret; + } + if (t == null) + { + if (src == null) + { + return new ObjectVariant(); + } + t = src.GetType(); + } + t = ElementedTypeHelper.TryGoToPointerOrReferenceElementType(t); + if (t == SimpleTypeHelper.ObjectType) + { + ret = new ObjectVariant(); + if (src != null && src.GetType() != SimpleTypeHelper.ObjectType) + { + ret.SetVariantType(src.GetType()); + } + } + else if (IsDerivedFrom<Array>(t)) + { + ret = new ArrayVariant(); + } + else if (IsDerivedFrom<string>(t)) + { + ret = new StringVariant(); + } + else if (IsDerivedFrom<IntPtr>(t)) + { + ret = new IntPtrVariant(); + } + else if (IsDerivedFrom<UIntPtr>(t)) + { + ret = new UIntPtrVariant(); + } + else if (IsDerivedFrom<ulong>(t)) + { + ret = new UlongVariant(); + } + else if (IsDerivedFrom<uint>(t)) + { + ret = new UintVariant(); + } + else if (IsDerivedFrom<ushort>(t)) + { + ret = new UshortVariant(); + } + else if (IsDerivedFrom<long>(t)) + { + ret = new LongVariant(); + } + else if (IsDerivedFrom<int>(t)) + { + ret = new IntVariant(); + } + else if (IsDerivedFrom<short>(t)) + { + ret = new ShortVariant(); + } + else if (IsDerivedFrom<byte>(t)) + { + ret = new ByteVariant(); + } + else if (IsDerivedFrom<sbyte>(t)) + { + ret = new SbyteVariant(); + } + else if (IsDerivedFrom<double>(t)) + { + ret = new DoubleVariant(); + } + else if (IsDerivedFrom<float>(t)) + { + ret = new FloatVariant(); + } + else if (IsDerivedFrom<bool>(t)) + { + ret = new BoolVariant(); + } + else if (IsDerivedFrom<char>(t)) + { + ret = new CharVariant(); + } + else if (SimpleTypeHelper.IsNullableGeneric(t)) + { + var ov = new ObjectVariant(); + ov.SetVariantType(t); + ret = ov; + } + else + { + if (IsDerivedFrom<Enum>(t)) + { + Enum e; + if (src == null) + { + e = (Enum)Activator.CreateInstance(t); + } + else if (t == SimpleTypeHelper.EnumType && src is Enum) + { + e = (Enum)src; + } + else + { + e = (Enum)Enum.ToObject(t, src); + } + return new EnumVariant(e); + } + if (IsDerivedFrom<ValueType>(t)) + { + if (src == null) + { + var vt = (t == SimpleTypeHelper.TypedReferenceType) ? + FormatterServices.GetSafeUninitializedObject(SimpleTypeHelper.TypedReferenceType) : + Activator.CreateInstance(t); + ret = new ValueTypeVariant(vt); + } + else + { + if (src.GetType() != t) + { + try + { + src = System.Convert.ChangeType(src, t); + } + catch + { + // ignored + } + } + ret = new ValueTypeVariant(src); + } + return ret; + } + ret = new ObjectVariant(); + } + if (src != null) + { + ret.SetValueAbstract(src); + } + return ret; + } + } +} diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VmExecutor.cs b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VmExecutor.cs new file mode 100644 index 0000000..7174a43 --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VmExecutor.cs @@ -0,0 +1,7505 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; +using System.Threading; + +// ReSharper disable InconsistentNaming +// ReSharper disable UnusedMember.Local +// ReSharper disable UnusedParameter.Local +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable EmptyGeneralCatchClause +// ReSharper disable RedundantCast +// ReSharper disable PossibleNullReferenceException +// ReSharper disable AssignNullToNotNullAttribute +// ReSharper disable UnusedMember.Global + +namespace UnitTestProject.RefVm +{ + // Token: 0x02000032 RID: 50 + public class VmExecutor // \u0006\u2007 + { + #region subclasses + + // Token: 0x02000033 RID: 51 + [Serializable] + private sealed class CatchBlockComparer // \u0002 + { + // Token: 0x060002B0 RID: 688 RVA: 0x00012EB4 File Offset: 0x000110B4 + internal int Compare(CatchBlock v1, CatchBlock v2) // \u0002 + { + if (v1.ExcTypeId == v2.ExcTypeId) + { + return v2.Start.CompareTo(v1.Start); + } + return v1.ExcTypeId.CompareTo(v2.ExcTypeId); + } + + // Token: 0x04000155 RID: 341 + public static readonly CatchBlockComparer Instance = new CatchBlockComparer(); // \u0002 + + // Token: 0x04000156 RID: 342 + public static Comparison<CatchBlock> MyComparison; // \u0003 + } + + // Token: 0x02000038 RID: 56 + private sealed class StringTypePair // \u0006 + { + // Token: 0x060002C0 RID: 704 RVA: 0x00013020 File Offset: 0x00011220 + // Token: 0x060002C1 RID: 705 RVA: 0x00013028 File Offset: 0x00011228 + // Token: 0x0400015D RID: 349 + public string Str { get; set; } // \u0002 + + // Token: 0x060002C3 RID: 707 RVA: 0x0001303C File Offset: 0x0001123C + // Token: 0x060002C2 RID: 706 RVA: 0x00013034 File Offset: 0x00011234 + // Token: 0x0400015E RID: 350 + public Type T { get; set; } // \u0002 + } + + // Token: 0x02000039 RID: 57 + // (Invoke) Token: 0x060002C5 RID: 709 + private delegate object DynamicExecutor(object obj, object[] args); // \u0008 + + // Token: 0x0200003A RID: 58 + // (Invoke) Token: 0x060002C9 RID: 713 + internal delegate void VmInstrImpl(VariantBase t); // \u000E + + // Token: 0x0200003B RID: 59 + private sealed class VmInstr // \u000F + { + // Token: 0x060002CC RID: 716 RVA: 0x00013048 File Offset: 0x00011248 + public VmInstr(VmInstrInfo id, VmInstrImpl func) + { + Id = id; + Func = func; + } + + // Token: 0x0400015F RID: 351 + public readonly VmInstrInfo Id; // \u0002 + + // Token: 0x04000160 RID: 352 + public readonly VmInstrImpl Func; // \u0003 + } + + // Token: 0x02000037 RID: 55 + private sealed class ExcHandlerFrame // \u0005 + { + // Token: 0x060002BB RID: 699 RVA: 0x00012FF0 File Offset: 0x000111F0 + // Token: 0x060002BC RID: 700 RVA: 0x00012FF8 File Offset: 0x000111F8 + // Token: 0x0400015B RID: 347 + public uint Pos { get; set; } + + // Token: 0x060002BD RID: 701 RVA: 0x00013004 File Offset: 0x00011204 + // Token: 0x060002BE RID: 702 RVA: 0x0001300C File Offset: 0x0001120C + // Token: 0x0400015C RID: 348 + public object Exception { get; set; } + } + + // Token: 0x02000034 RID: 52 + internal struct MethodBaseAndVirtual : IEquatable<MethodBaseAndVirtual> // \u0002\u2000 + { + public MethodBaseAndVirtual(MethodBase mb, bool isVirtual) + { + Val = mb; + IsVirtual = isVirtual; + } + + // Token: 0x060002B1 RID: 689 RVA: 0x00012EF8 File Offset: 0x000110F8 + // Token: 0x060002B2 RID: 690 RVA: 0x00012F00 File Offset: 0x00011100 + // Token: 0x04000157 RID: 343 + public MethodBase Val /* \u0002 */ { get; } + + // Token: 0x060002B3 RID: 691 RVA: 0x00012F0C File Offset: 0x0001110C + // Token: 0x060002B4 RID: 692 RVA: 0x00012F14 File Offset: 0x00011114 + // Token: 0x04000158 RID: 344 + public bool IsVirtual /* \u0003 */ { get; } + + // Token: 0x060002B5 RID: 693 RVA: 0x00012F20 File Offset: 0x00011120 + public override int GetHashCode() + { + return Val.GetHashCode() ^ IsVirtual.GetHashCode(); + } + + // Token: 0x060002B6 RID: 694 RVA: 0x00012F48 File Offset: 0x00011148 + public override bool Equals(object o) + { + if (o is MethodBaseAndVirtual) + { + return Equals((MethodBaseAndVirtual)o); + } + return false; + } + + // Token: 0x060002B7 RID: 695 RVA: 0x00012F70 File Offset: 0x00011170 + public bool Equals(MethodBaseAndVirtual val) + { + return IsVirtual == val.IsVirtual && Val == val.Val; + } + } + + // Token: 0x02000035 RID: 53 + private struct BoolHolder // \u0003 + { + // Token: 0x04000159 RID: 345 + public bool Val; // \u0002 + } + + // Token: 0x02000036 RID: 54 + private sealed class IntToTypeComparer<T> : IComparer<KeyValuePair<int, T>> // \u0003\u2000 + { + // Token: 0x060002B8 RID: 696 RVA: 0x00012F94 File Offset: 0x00011194 + public IntToTypeComparer(Comparison<T> c) + { + _c = c; + } + + // Token: 0x060002B9 RID: 697 RVA: 0x00012FA4 File Offset: 0x000111A4 + public int Compare(KeyValuePair<int, T> v1, KeyValuePair<int, T> v2) + { + var num = _c(v1.Value, v2.Value); + if (num == 0) + { + return v2.Key.CompareTo(v1.Key); + } + return num; + } + + // Token: 0x0400015A RID: 346 + private readonly Comparison<T> _c; + } + + // Token: 0x0200000B RID: 11 + private static class HiByte // \u0002\u2008 + { + // Token: 0x06000056 RID: 86 RVA: 0x00003154 File Offset: 0x00001354 + public static int Extract(int src) // \u0002 + { + return src & -16777216; // 0xFF000000 + } + } + + #endregion + + #region members + // Token: 0x04000132 RID: 306 + private static readonly Type MethodBaseType = typeof(MethodBase); // \u0002\u2001 + + // Token: 0x04000133 RID: 307 + private VmMethodHeader _methodHeader; // \u000E + + // Token: 0x04000134 RID: 308 + private readonly MyCollection<VariantBase> _evalStack = new MyCollection<VariantBase>(); // \u0003\u2003 + + // Token: 0x04000135 RID: 309 + private readonly Dictionary<int, object> AllMetadataById = new Dictionary<int, object>(); // \u0006\u2003 + + // Token: 0x04000136 RID: 310 + private readonly VmInstrCodesDb _instrCodesDb; // \u0006\u2001 + + // Token: 0x04000137 RID: 311 + private object _exception; // \u0006\u2002 + + // Token: 0x04000138 RID: 312 + private readonly Dictionary<MethodBase, object> _mbDynamicLock = new Dictionary<MethodBase, object>(); // \u0008\u2002 + + // Token: 0x04000139 RID: 313 + private BinaryReader _srcVirtualizedStreamReader; // \u0002\u2000 + + // Token: 0x0400013A RID: 314 + private Type _currentClass; // \u000F\u2001 + + // Token: 0x0400013B RID: 315 + private static readonly Type AssemblyType = typeof(Assembly); // \u0002\u2003 + + // Token: 0x0400013C RID: 316 + private readonly Dictionary<MethodBase, int> _mbCallCnt = new Dictionary<MethodBase, int>(256); // \u0006 + + // Token: 0x0400013D RID: 317 + private Stream _srcVirtualizedStream; // \u000F\u2000 + + // Token: 0x0400013E RID: 318 + private object[] _callees; // \u0005\u2000 + + // Token: 0x0400013F RID: 319 + private readonly MyCollection<ExcHandlerFrame> _ehStack = new MyCollection<ExcHandlerFrame>(); // \u000F + + // Token: 0x04000140 RID: 320 + private VariantBase[] _localVariables; // \u0003\u2002 + + // Token: 0x04000141 RID: 321 + private readonly Dictionary<MethodBaseAndVirtual, DynamicExecutor> _dynamicExecutors = new Dictionary<MethodBaseAndVirtual, DynamicExecutor>(256); // \u0002\u2002 + + // Token: 0x04000142 RID: 322 + private bool _retFound; // \u0005\u2003 + + // Token: 0x04000143 RID: 323 + private MyBufferReader _myBufferReader; // \u0002 + + // Token: 0x04000144 RID: 324 + private Type[] _classGenericArgs; // \u0003 + + // Token: 0x04000145 RID: 325 + private readonly Module _module; // \u0008\u2001 + + // Token: 0x04000146 RID: 326 + private long _myBufferPos; // \u0005 + + // Token: 0x04000147 RID: 327 + private byte[] _methodBody; // \u0008 + + // Token: 0x04000148 RID: 328 + private static readonly Type ObjectArrayType = typeof(object[]); // \u000E\u2001 + + // Token: 0x04000149 RID: 329 + private static readonly Dictionary<MethodBase, DynamicMethod> DynamicMethods = new Dictionary<MethodBase, DynamicMethod>(); // \u000E\u2003 + + // Token: 0x0400014A RID: 330 + private bool _wasException; // \u0008\u2000 + + // Token: 0x0400014B RID: 331 + private Type[] _methodGenericArgs; // \u0005\u2001 + + // Token: 0x0400014C RID: 332 + private CatchBlock[] _catchBlocks; // \u000F\u2003 + + // Token: 0x0400014D RID: 333 + private static readonly object InterlockedLock = new object(); // \u0008\u2003 + + // Token: 0x0400014E RID: 334 + private uint? _storedPos; // \u000E\u2000 + + // Token: 0x0400014F RID: 335 + private const bool _alwaysFalse = false; // \u000F\u2002 + + // Token: 0x04000150 RID: 336 + private Dictionary<int, VmInstr> _vmInstrDb; // \u000E\u2002 + + // Token: 0x04000151 RID: 337 + private VariantBase[] _variantOutputArgs; // \u0005\u2002 + + // Token: 0x04000152 RID: 338 + private const bool _alwaysTrue = true; // \u0003\u2001 + + // Token: 0x04000153 RID: 339 + private static readonly Type IntPtrType = typeof(IntPtr); // \u0003\u2000 + + // Token: 0x04000154 RID: 340 + private static readonly Type VoidType = typeof(void); // \u0006\u2000 + + #endregion + + // Token: 0x0600016C RID: 364 RVA: 0x00007958 File Offset: 0x00005B58 + public VmExecutor(VmInstrCodesDb instrCodesDb, Module m) + { + _instrCodesDb = instrCodesDb; + _module = m; + Init(); + } + + // Token: 0x060001B6 RID: 438 RVA: 0x000092E0 File Offset: 0x000074E0 + private void Init() // \u000F + { + if (!_instrCodesDb.IsInitialized()) + { + lock (_instrCodesDb) + { + if (!_instrCodesDb.IsInitialized()) + { + _vmInstrDb = CreateVmInstrDb(); + DoNothing(); + _instrCodesDb.SetInitialized(true); + } + } + } + if (_vmInstrDb == null) + { + _vmInstrDb = CreateVmInstrDb(); + } + } + + // Token: 0x060001BD RID: 445 RVA: 0x00009534 File Offset: 0x00007734 + private void DoNothing() // \u0006 + {} + + // Token: 0x06000239 RID: 569 RVA: 0x0000F9C4 File Offset: 0x0000DBC4 + private VariantBase PopVariant() // \u0002 + { + return _evalStack.PopBack(); + } + + // Token: 0x060002A0 RID: 672 RVA: 0x000127D8 File Offset: 0x000109D8 + private long PopLong() // \u0002 + { + var top = PopVariant(); + switch (top.GetTypeCode()) + { + case VariantBase.Vtc.Tc5Enum: return VariantBase.SignedLongFromEnum((EnumVariant)top); // bug was fixed and unit tested (Convert.ToInt64(((EnumVariant)top).GetValue());) + case VariantBase.Vtc.Tc13UIntPtr: return (long)((UIntPtrVariant)top).GetValue().ToUInt64(); + case VariantBase.Vtc.Tc17IntPtr: return ((IntPtrVariant)top).GetValue().ToInt64(); + case VariantBase.Vtc.Tc19Int: return ((IntVariant)top).GetValue(); + } + throw new Exception(StringDecryptor.GetString(-1550345551) /* Unexpected value on the stack. */); + } + + // Token: 0x060001A1 RID: 417 RVA: 0x00008CC4 File Offset: 0x00006EC4 + private void Ldelem(Type t) // \u0002 + { + var index = PopLong(); + var array = (Array)PopVariant().GetValueAbstract(); + PushVariant(VariantFactory.Convert(array.GetValue(index), t)); + } + + // Token: 0x0600020C RID: 524 RVA: 0x0000C528 File Offset: 0x0000A728 + private void Ldelem_(VariantBase vTypeId) // \u0006\u200A\u2000 + { + var typeId = ((IntVariant)vTypeId).GetValue(); + var type = GetTypeById(typeId); + Ldelem(type); + } + + // Token: 0x060002A5 RID: 677 RVA: 0x00012A80 File Offset: 0x00010C80 + private void PushVariant(VariantBase obj) // \u0008\u2000\u2001 + { + if (obj == null) + { + throw new ArgumentNullException(StringDecryptor.GetString(-1550345950) /* obj */); + } + VariantBase push; + if (obj.GetVariantType() != null) + { + push = obj; + } + else + { + switch (obj.GetTypeCode()) + { + case VariantBase.Vtc.Tc1Bool: + { + var tmp = new IntVariant(); + tmp.SetValue(((BoolVariant)obj).GetValue() ? 1 : 0); + tmp.SetVariantType(obj.GetVariantType()); + push = tmp; + break; + } + case VariantBase.Vtc.Tc6Char: + { + var tmp = new IntVariant(); + tmp.SetValue(((CharVariant)obj).GetValue()); + tmp.SetVariantType(obj.GetVariantType()); + push = tmp; + break; + } + case VariantBase.Vtc.Tc7Ulong: + { + var tmp = new LongVariant(); + tmp.SetValue((long)((UlongVariant)obj).GetValue()); + tmp.SetVariantType(obj.GetVariantType()); + push = tmp; + break; + } + case VariantBase.Vtc.Tc8Float: + { + var tmp = new FloatVariant(); + tmp.SetValue(((FloatVariant)obj).GetValue()); + tmp.SetVariantType(obj.GetVariantType()); + push = tmp; + break; + } + case VariantBase.Vtc.Tc9Uint: + { + var tmp = new IntVariant(); + tmp.SetValue((int)((UintVariant)obj).GetValue()); + tmp.SetVariantType(obj.GetVariantType()); + push = tmp; + break; + } + case VariantBase.Vtc.Tc10Ushort: + { + var tmp = new IntVariant(); + tmp.SetValue(((UshortVariant)obj).GetValue()); + tmp.SetVariantType(obj.GetVariantType()); + push = tmp; + break; + } + case VariantBase.Vtc.Tc12Sbyte: + { + var tmp = new IntVariant(); + tmp.SetValue(((SbyteVariant)obj).GetValue()); + tmp.SetVariantType(obj.GetVariantType()); + push = tmp; + break; + } + case VariantBase.Vtc.Tc14Byte: + { + var tmp = new IntVariant(); + tmp.SetValue(((ByteVariant)obj).GetValue()); + tmp.SetVariantType(obj.GetVariantType()); + push = tmp; + break; + } + case VariantBase.Vtc.Tc15Short: + { + var tmp = new IntVariant(); + tmp.SetValue(((ShortVariant)obj).GetValue()); + tmp.SetVariantType(obj.GetVariantType()); + push = tmp; + break; + } + case VariantBase.Vtc.Tc18Object: + { + var abs = obj.GetValueAbstract(); + if (abs == null) + { + push = obj; + break; + } + var type = abs.GetType(); + if (type.HasElementType && !type.IsArray) + { + type = type.GetElementType(); + } + if (type != null && !type.IsValueType && !type.IsEnum) + { + push = obj; + break; + } + push = VariantFactory.Convert(abs, type); + break; + } + case VariantBase.Vtc.Tc17IntPtr: + case VariantBase.Vtc.Tc13UIntPtr: + if(IntPtr.Size == 4) + { + var tmp = new IntVariant(); + tmp.CopyFrom(obj); + tmp.SetVariantType(obj.GetVariantType()); + push = tmp; + } + else + { + var tmp = new LongVariant(); + tmp.CopyFrom(obj); + tmp.SetVariantType(obj.GetVariantType()); + push = tmp; + } + break; + default: + push = obj; + break; + } + } + _evalStack.PushBack(push); + } + + // Token: 0x0600027D RID: 637 RVA: 0x00011C24 File Offset: 0x0000FE24 + private void Conv_ovf_i4_un_(VariantBase dummy) // \u0003\u200B + { + Conv_i4(true, false); + } + + // Token: 0x06000283 RID: 643 RVA: 0x00011E9C File Offset: 0x0001009C + public static void Sort<T>(T[] arr, Comparison<T> c) // \u0002 + { + var array = new KeyValuePair<int, T>[arr.Length]; + for (var i = 0; i < arr.Length; i++) + { + array[i] = new KeyValuePair<int, T>(i, arr[i]); + } + Array.Sort(array, arr, new IntToTypeComparer<T>(c)); + } + + // Token: 0x060001BE RID: 446 RVA: 0x00009538 File Offset: 0x00007738 + private void SortCatchBlocks() // \u0003\u2000 + { + if (CatchBlockComparer.MyComparison == null) + { + CatchBlockComparer.MyComparison = CatchBlockComparer.Instance.Compare; + } + Sort(_catchBlocks, CatchBlockComparer.MyComparison); + } + + // Token: 0x0600016D RID: 365 RVA: 0x000079C8 File Offset: 0x00005BC8 + public VmExecutor(VmInstrCodesDb instrCodesDb, Stream virtualizedStream = null) : this(instrCodesDb, typeof(VmExecutor).Module) // \u0006\u2007 + { + _srcVirtualizedStream = virtualizedStream; + } + + // Token: 0x0600023C RID: 572 RVA: 0x0000FA0C File Offset: 0x0000DC0C + public object Invoke(Stream virtualizedStream, string pos, object[] args) // \u0002 + { + // ReSharper disable once IntroduceOptionalParameters.Global + return Invoke(virtualizedStream, pos, args, null, null, null); + } + + // Token: 0x0600017A RID: 378 RVA: 0x00007DCC File Offset: 0x00005FCC + public object Invoke(Stream virtualizedStream, string pos, object[] args, Type[] methodGenericArgs, Type[] classGenericArgs, object[] callees) // \u0002 + { + _srcVirtualizedStream = virtualizedStream; + Seek(pos, virtualizedStream); + return Invoke(args, methodGenericArgs, classGenericArgs, callees); + } + + // Token: 0x060001C5 RID: 453 RVA: 0x00009A34 File Offset: 0x00007C34 + private Type GetTypeById(int id) // \u0002 + { + Type result; + lock (AllMetadataById) + { + var flag = true; + object o; + if (AllMetadataById.TryGetValue(id, out o)) + { + result = (Type)o; + } + else + { + var token = ReadToken(id); + if (token.IsVm == 0) + { + var type = _module.ResolveType(token.MetadataToken); + AllMetadataById.Add(id, type); + result = type; + } + else + { + var vmToken = (VmClassTokenInfo)token.VmToken; + if (vmToken.IsOuterClassGeneric) + { + if (vmToken.OuterClassGenericMethodIdx!= -1) + { + result = _methodGenericArgs[vmToken.OuterClassGenericMethodIdx]; + } + else + { + if (vmToken.OuterClassGenericClassIdx== -1) + { + throw new Exception(); + } + result = _classGenericArgs[vmToken.OuterClassGenericClassIdx]; + } + result = ElementedTypeHelper.PopType(result, ElementedTypeHelper.NestedElementTypes(vmToken.ClassName)); + } + else + { + var className = vmToken.ClassName.Replace("\u0005 ,", "forms_cil.Trial,"); //TODO: в общем случае это лишнее + result = Type.GetType(className); + if (result == null) + { + var num = className.IndexOf(','); + var shortClassName = className.Substring(0, num); + var asmName = className.Substring(num + 1, className.Length - num - 1).Trim(); + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + foreach (var assembly in assemblies) + { + string value = null; + try + { + value = assembly.Location; + } + catch (NotSupportedException) + { + } + if (string.IsNullOrEmpty(value) && assembly.FullName.Equals(asmName, StringComparison.Ordinal)) + { + result = assembly.GetType(shortClassName); + if (result != null) + { + break; + } + } + } + if (result == null && shortClassName.StartsWith(StringDecryptor.GetString(-1550345235) /* <PrivateImplementationDetails>< */, StringComparison.Ordinal) && shortClassName.Contains(StringDecryptor.GetString(-1550345325) /* . */)) + { + try + { + var types = Assembly.Load(asmName).GetTypes(); + foreach (var t in types.Where(type3 => type3.FullName == shortClassName)) + { + result = t; + break; + } + } + // ReSharper disable once EmptyGeneralCatchClause + catch + { + } + } + } + if (vmToken.IsGeneric) + { + var array = new Type[vmToken.GenericArguments.Length]; + for (var j = 0; j < vmToken.GenericArguments.Length; j++) + { + array[j] = GetTypeById(vmToken.GenericArguments[j].MetadataToken); + } + var genericTypeDefinition = ElementedTypeHelper.TryGoToElementType(result).GetGenericTypeDefinition(); + var c = ElementedTypeHelper.NestedElementTypes(result); + result = ElementedTypeHelper.PopType(genericTypeDefinition.MakeGenericType(array), c); + flag = false; + } + if (flag) + { + AllMetadataById.Add(id, result); + } + } + } + } + } + return result; + } + + // Token: 0x060001A6 RID: 422 RVA: 0x00008DAC File Offset: 0x00006FAC + public object Invoke(object[] args, Type[] methodGenericArgs, Type[] classGenericArgs, object[] callees) // \u0002 + { + if (args == null) + { + args = EmptyArray<object>.Data; + } + if (methodGenericArgs == null) + { + methodGenericArgs = Type.EmptyTypes; + } + if (classGenericArgs == null) + { + classGenericArgs = Type.EmptyTypes; + } + _callees = callees; + _methodGenericArgs = methodGenericArgs; + _classGenericArgs = classGenericArgs; + _variantOutputArgs = ArgsToVariantOutputArgs(args); + _localVariables = CreateLocalVariables(); + object result; + try + { + using (var b = new MyBuffer(_methodBody)) + { + using (_myBufferReader = new MyBufferReader(b)) + { + _retFound = false; + _storedPos = null; + _evalStack.Clear(); + InternalInvoke(); + } + } + var retType = GetTypeById(_methodHeader.ReturnTypeId); + if (retType != VoidType && _evalStack.Count > 0) + { + var pop = PopVariant(); + try + { + result = VariantFactory.Convert(null, retType).CopyFrom(pop).GetValueAbstract(); + } + catch (Exception) + { + result = pop.GetValueAbstract(); // example: ckfinite with no numeric + //throw; + } + } + else + { + result = null; + } + } + finally + { + for (var i = 0; i < _methodHeader.ArgsTypeToOutput.Length; i++) + { + var argTypeToOutput = _methodHeader.ArgsTypeToOutput[i]; + if (argTypeToOutput.IsOutput) + { + var argOutValue = (VariantBaseHolder)_variantOutputArgs[i]; + var argType = GetTypeById(argTypeToOutput.TypeId); + args[i] = VariantFactory.Convert(null, argType.GetElementType()).CopyFrom(argOutValue.GetValue()).GetValueAbstract(); + } + } + _callees = null; + _variantOutputArgs = null; + _localVariables = null; + } + return result; + } + + // Token: 0x06000269 RID: 617 RVA: 0x00010F7C File Offset: 0x0000F17C + private void Seek(string pos, Stream virtualizedStream) // \u0002 + { + Seek(0L, virtualizedStream, pos); + } + + // Token: 0x0600025C RID: 604 RVA: 0x00010B38 File Offset: 0x0000ED38 + private void DoNothing(BinaryReader dummy) // \u0002 + { + } + + // Token: 0x06000250 RID: 592 RVA: 0x000106EC File Offset: 0x0000E8EC + private static CatchBlock ReadCatchBlock(BinaryReader r) // \u0002 + { + return new CatchBlock + { + Kind = r.ReadByte(), + ExcTypeId = r.ReadInt32(), + Pos = r.ReadUInt32(), + PosKind4 = r.ReadUInt32(), + Start = r.ReadUInt32(), + Len = r.ReadUInt32() + }; + } + + // Token: 0x060001FC RID: 508 RVA: 0x0000BD50 File Offset: 0x00009F50 + private static CatchBlock[] ReadCatchBlocks(BinaryReader r) // \u0002 + { + var num = (int)r.ReadInt16(); + var array = new CatchBlock[num]; + for (var i = 0; i < num; i++) + { + array[i] = ReadCatchBlock(r); + } + return array; + } + + // Token: 0x060001BF RID: 447 RVA: 0x00009564 File Offset: 0x00007764 + private static byte[] ReadByteArray(BinaryReader r) // \u0002 + { + var num = r.ReadInt32(); + var array = new byte[num]; + r.Read(array, 0, num); + return array; + } + + // Token: 0x060001C1 RID: 449 RVA: 0x000096E4 File Offset: 0x000078E4 + public void Seek(long parsedPos, Stream virtualizedStream, string pos) // \u0002 + { + var input = new VmStreamWrapper(virtualizedStream, VmXorKey()); + _srcVirtualizedStreamReader = new BinaryReader(input); + var baseStream = _srcVirtualizedStreamReader.BaseStream; + lock (baseStream) + { + if (pos != null) + { + parsedPos = ParsePos(pos); + } + _srcVirtualizedStreamReader.BaseStream.Seek(parsedPos, SeekOrigin.Begin); + DoNothing(_srcVirtualizedStreamReader); + _methodHeader = ReadMethodHeader(_srcVirtualizedStreamReader); + _catchBlocks = ReadCatchBlocks(_srcVirtualizedStreamReader); + SortCatchBlocks(); + _methodBody = ReadByteArray(_srcVirtualizedStreamReader); + } + } + + // Token: 0x06000203 RID: 515 RVA: 0x0000C164 File Offset: 0x0000A364 + private long ParsePos(string pos) // \u0002 + { + using (var memoryStream = new MemoryStream(VmPosParser.Parse(pos))) + { + return new BinaryReader(new VmStreamWrapper(memoryStream, PosXorKey())).ReadInt64(); + } + } + + // Token: 0x060001B5 RID: 437 RVA: 0x000092D8 File Offset: 0x000074D8 + private int PosXorKey() // \u0002 + { + return -2023764088; + } + + // Token: 0x0600017B RID: 379 RVA: 0x00007DEC File Offset: 0x00005FEC + public static int VmXorKey() // \u0003 + { + return 1783652397; + } + + // Token: 0x060001E7 RID: 487 RVA: 0x0000B0F8 File Offset: 0x000092F8 + private LocalVarType ReadLocalVarType(BinaryReader r) // \u0002 + { + return new LocalVarType { TypeId = r.ReadInt32() }; + } + + // Token: 0x060001AB RID: 427 RVA: 0x00008FF8 File Offset: 0x000071F8 + private LocalVarType[] ReadLocalVarTypes(BinaryReader r) // \u0002 + { + var array = new LocalVarType[r.ReadInt16()]; + for (var i = 0; i < array.Length; i++) + { + array[i] = ReadLocalVarType(r); + } + return array; + } + + // Token: 0x0600023B RID: 571 RVA: 0x0000F9E0 File Offset: 0x0000DBE0 + private ArgTypeToOutput ReadArgTypeToOutput(BinaryReader r) // \u0002 + { + var ret = new ArgTypeToOutput + { + TypeId = r.ReadInt32(), + IsOutput = r.ReadBoolean() + }; + return ret; + } + + // Token: 0x06000287 RID: 647 RVA: 0x00012138 File Offset: 0x00010338 + private ArgTypeToOutput[] ReadArgsTypeToOutput(BinaryReader r) // \u0002 + { + var array = new ArgTypeToOutput[r.ReadInt16()]; + for (var i = 0; i < array.Length; i++) + { + array[i] = ReadArgTypeToOutput(r); + } + return array; + } + + // Token: 0x06000216 RID: 534 RVA: 0x0000C790 File Offset: 0x0000A990 + private VmMethodHeader ReadMethodHeader(BinaryReader src) // \u0002 + { + var ret = new VmMethodHeader + { + ClassId = src.ReadInt32(), + ReturnTypeId = src.ReadInt32(), + LocalVarTypes = ReadLocalVarTypes(src), + Flags = src.ReadByte(), + Name = src.ReadString(), + ArgsTypeToOutput = ReadArgsTypeToOutput(src) + }; + return ret; + } + + // Token: 0x06000266 RID: 614 RVA: 0x00010C54 File Offset: 0x0000EE54 + private void Shr_un_(VariantBase dummy) // \u000F\u2001 + { + PushVariant(Shift(false, false)); + } + + // Token: 0x06000176 RID: 374 RVA: 0x00007CAC File Offset: 0x00005EAC + private void Shr_(VariantBase dummy) // \u0005\u2007\u2000 + { + PushVariant(Shift(false, true)); + } + + private VariantBase Xor(VariantBase org_v1, VariantBase org_v2) + { + VariantBase v1, v2; + var tc = CommonType(org_v1, org_v2, out v1, out v2, true); + VariantBase ret; + switch (tc) + { + case VariantBase.Vtc.Tc9Uint: + uint uv1 = ((UintVariant)v1).GetValue(), uv2 = ((UintVariant)v2).GetValue(); + var uvret = new UintVariant(); + ret = uvret; + uvret.SetValue(uv1 ^ uv2); + break; + case VariantBase.Vtc.Tc19Int: + int iv1 = ((IntVariant)v1).GetValue(), iv2 = ((IntVariant)v2).GetValue(); + var ivret = new IntVariant(); + ret = ivret; + ivret.SetValue(iv1 ^ iv2); + break; + case VariantBase.Vtc.Tc21Double: + { + /*double dv1 = ((DoubleVariant)v1).GetValue(), dv2 = ((DoubleVariant)v2).GetValue(); // естественный алгоритм + long lv1 = (dv1 < 0) ? (long)dv1 : (long)(ulong)dv1; + long lv2 = (dv2 < 0) ? (long)dv2 : (long)(ulong)dv2; + var dvret = new DoubleVariant(); + ret = dvret; + var l64 = (ulong) lv1 ^ (ulong) lv2; + if (l64 >> 32 == UInt32.MaxValue) l64 &= UInt32.MaxValue; + dvret.SetValue(l64);*/ + var dvret = new DoubleVariant(); + ret = dvret; + dvret.SetValue((4 == IntPtr.Size) ? Double.NaN : (double)0); // иногда у фреймворка бывает мусор, но чаще эти значения... + } + break; + case VariantBase.Vtc.Tc8Float: + { + /*float fv1 = ((FloatVariant) v1).GetValue(), fv2 = ((FloatVariant) v2).GetValue(); // естественный алгоритм + long lv1 = (fv1 < 0) ? (long)fv1 : (long)(ulong)fv1; + long lv2 = (fv2 < 0) ? (long)fv2 : (long)(ulong)fv2; + var fvret = new FloatVariant(); + ret = fvret; + var l64 = (ulong)lv1 ^ (ulong)lv2; + if (l64 >> 32 == UInt32.MaxValue) l64 &= UInt32.MaxValue; + fvret.SetValue(l64);*/ + var fvret = new FloatVariant(); + ret = fvret; + fvret.SetValue((4 == IntPtr.Size) ? float.NaN : (float)0.0); // иногда у фреймворка бывает мусор, но чаще эти значения... + } + break; + case VariantBase.Vtc.Tc24Long: + { + long lv1 = ((LongVariant)v1).GetValue(), lv2 = ((LongVariant)v2).GetValue(); + var lvret = new LongVariant(); + ret = lvret; + lvret.SetValue(lv1 ^ lv2); + } + break; + case VariantBase.Vtc.Tc7Ulong: + ulong ulv1 = ((UlongVariant)v1).GetValue(), ulv2 = ((UlongVariant)v2).GetValue(); + var ulvret = new UlongVariant(); + ret = ulvret; + ulvret.SetValue(ulv1 ^ ulv2); + break; + default: + // это нужно будет заменить на соотв. msil-код + var dyn = new DynamicMethod(String.Empty, typeof(IntPtr), new[] { typeof(object), typeof(object) }, typeof(void), true); + var gen = dyn.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_1); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(OpCodes.Xor); + gen.Emit(OpCodes.Ret); + ret = new IntPtrVariant(); + ((IntPtrVariant)ret).SetValue(((IntPtr)dyn.Invoke(null, new[] { org_v1.GetValueAbstract(), org_v2.GetValueAbstract() }))); + break; + } + return ret; + } + + // Token: 0x0600026C RID: 620 RVA: 0x00010FC8 File Offset: 0x0000F1C8 + private void Xor_(VariantBase dummy) // \u0008\u2001\u2000 + { + var v1 = PopVariant(); + var v2 = PopVariant(); + PushVariant(Xor(v2, v1)); + } + + // Token: 0x06000189 RID: 393 RVA: 0x00008244 File Offset: 0x00006444 + private void Shl_(VariantBase dummy) // \u0006\u2002\u2001 + { + PushVariant(Shift(true, true)); + } + + VariantBase.Vtc CommonTypeShift(VariantBase org_val, VariantBase org_shift, out VariantBase val, out VariantBase shift, bool signed) + { + val = org_val.Clone(); + shift = org_shift.Clone(); + var tcval = UnderlyingTypeCode(ref val); + var tcsh = UnderlyingTypeCode(ref shift); + if (tcval == VariantBase.Vtc.Tc18Object || tcsh == VariantBase.Vtc.Tc18Object) + return VariantBase.Vtc.Tc18Object; + shift = new LongVariant(); + long lsh = 0; + switch (org_shift.GetTypeCode()) + { + case VariantBase.Vtc.Tc5Enum: + lsh = VariantBase.SignedLongFromEnum((EnumVariant) org_shift); + break; + case VariantBase.Vtc.Tc13UIntPtr: + lsh = (long)((UIntPtrVariant)org_shift).GetValue().ToUInt64(); + break; + case VariantBase.Vtc.Tc17IntPtr: + lsh = ((IntPtrVariant)org_shift).GetValue().ToInt64(); + break; + case VariantBase.Vtc.Tc19Int: + lsh = ((IntVariant)org_shift).GetValue(); + break; + case VariantBase.Vtc.Tc24Long: + lsh = ((LongVariant)org_shift).GetValue(); + break; + } + shift.SetValueAbstract(lsh); + VariantBase.Vtc ret = tcval; + if (!signed) + { + val = AsUnsigned(val); + } + if (!signed) switch (ret) + { + case VariantBase.Vtc.Tc19Int: + return VariantBase.Vtc.Tc9Uint; + case VariantBase.Vtc.Tc24Long: + return VariantBase.Vtc.Tc7Ulong; + } + return ret; + } + + private VariantBase Shift(bool left, bool signed) + { + VariantBase val, shift; + + var org_shift = PopVariant(); + var org_val = PopVariant(); + var tc = CommonTypeShift(org_val, org_shift, out val, out shift, signed); + var sh = (int)(long)shift.GetValueAbstract(); + VariantBase ret; + switch (tc) + { + case VariantBase.Vtc.Tc9Uint: + uint uv1 = ((UintVariant)val).GetValue(); + var uvret = new UintVariant(); + ret = uvret; + if (left) + { + uvret.SetValue(uv1 << sh); + } + else + { + uvret.SetValue(uv1 >> sh); + } + break; + case VariantBase.Vtc.Tc19Int: + int iv1 = ((IntVariant)val).GetValue(); + var ivret = new IntVariant(); + ret = ivret; + if (left) + { + ivret.SetValue(iv1 << sh); + } + else + { + ivret.SetValue(iv1 >> sh); + } + break; + case VariantBase.Vtc.Tc21Double: + /*double dv1 = ((DoubleVariant)val).GetValue(), dv2 = ((DoubleVariant)shift).GetValue(); + var dvret = new DoubleVariant(); + ret = dvret; + var dmul = left ? 2 : 0.5; + dvret.SetValue(dv1 * Math.Pow(dmul, dv2)); + break;*/ + case VariantBase.Vtc.Tc8Float: + /*float fv1 = ((FloatVariant)val).GetValue(), fv2 = ((FloatVariant)shift).GetValue(); + var fvret = new FloatVariant(); + ret = fvret; + var fmul = left ? 2f : 0.5f; + fvret.SetValue(fv1 * (float)Math.Pow(fmul, fv2)); + break;*/ + throw new InvalidProgramException(); + case VariantBase.Vtc.Tc24Long: + long lv1 = ((LongVariant)val).GetValue(); + var lvret = new LongVariant(); + ret = lvret; + if (left) + { + lvret.SetValue(lv1 << sh); + } + else + { + lvret.SetValue(lv1 >> sh); + } + break; + case VariantBase.Vtc.Tc7Ulong: + ulong ulv1 = ((UlongVariant)val).GetValue(); + var ulvret = new UlongVariant(); + ret = ulvret; + if (left) + { + ulvret.SetValue(ulv1 << sh); + } + else + { + ulvret.SetValue(ulv1 >> sh); + } + break; + default: + // это нужно будет заменить на соотв. msil-код + var dyn = new DynamicMethod(String.Empty, typeof(IntPtr), new[] { typeof(object), typeof(object) }, typeof(void), true); + var gen = dyn.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_1); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(signed ? (left ? OpCodes.Shl : OpCodes.Shr) : OpCodes.Shr_Un); + gen.Emit(OpCodes.Ret); + ret = new IntPtrVariant(); + ((IntPtrVariant)ret).SetValue(((IntPtr)dyn.Invoke(null, new[] { org_val.GetValueAbstract(), org_shift.GetValueAbstract() }))); + break; + } + return ret; + } + + // Token: 0x06000173 RID: 371 RVA: 0x00007BE0 File Offset: 0x00005DE0 + private void Initblk_(VariantBase dummy) // \u0002\u2002\u2000 + { + throw new NotSupportedException(StringDecryptor.GetString(-1550345287) /* Initblk not supported. */); + } + + // Token: 0x0600020A RID: 522 RVA: 0x0000C508 File Offset: 0x0000A708 + private void Localloc_(VariantBase dummy) // \u0008\u200A\u2000 + { + throw new NotSupportedException(StringDecryptor.GetString(-1550345866) /* Localloc not supported. */); + } + + // Token: 0x06000212 RID: 530 RVA: 0x0000C73C File Offset: 0x0000A93C + private void Refanyval_(VariantBase dummy) // \u0005\u200A\u2000 + { + throw new NotSupportedException(StringDecryptor.GetString(-1550345900) /* Refanyval is not supported. */); + } + + // Token: 0x06000237 RID: 567 RVA: 0x0000F984 File Offset: 0x0000DB84 + private void Refanytype_(VariantBase dummy) // \u000F\u2005 + { + throw new NotSupportedException(StringDecryptor.GetString(-1550345460) /* Refanytype is not supported. */); + } + + // Token: 0x0600029C RID: 668 RVA: 0x000126CC File Offset: 0x000108CC + private void Cpblk_(VariantBase dummy) // \u0002\u2006 + { + throw new NotSupportedException(StringDecryptor.GetString(-1550345423) /* Cpblk not supported. */); + } + + // Token: 0x060001CA RID: 458 RVA: 0x00009E68 File Offset: 0x00008068 + private void Cpobj_(VariantBase dummy) // \u0008\u2009 + { + throw new NotSupportedException(StringDecryptor.GetString(-1550345317) /* Cpobj is not supported. */); + } + + // Token: 0x060001D2 RID: 466 RVA: 0x0000A338 File Offset: 0x00008538 + private void Arglist_(VariantBase dummy) // \u000F\u2002\u2001 + { + throw new NotSupportedException(StringDecryptor.GetString(-1550345940) /* Arglist is not supported. */); + } + + // Token: 0x06000187 RID: 391 RVA: 0x00008224 File Offset: 0x00006424 + private void Mkrefany_(VariantBase dummy) // \u0002\u2007 + { + throw new NotSupportedException(StringDecryptor.GetString(-1550345270) /* Mkrefany is not supported. */); + } + + // Token: 0x0600017E RID: 382 RVA: 0x00007ECC File Offset: 0x000060CC + private static BindingFlags BF(bool isStatic) // \u0002 + { + var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic; + if (isStatic) + { + bindingFlags |= BindingFlags.Static; + } + else + { + bindingFlags |= BindingFlags.Instance; + } + return bindingFlags; + } + + // Token: 0x06000192 RID: 402 RVA: 0x000084F4 File Offset: 0x000066F4 + private void Ldc_i4_0_(VariantBase dummy) // \u0005\u2001 + { + var iv = new IntVariant(); + iv.SetValue(0); + PushVariant(iv); + } + + // Token: 0x0600028F RID: 655 RVA: 0x0001235C File Offset: 0x0001055C + private void Ldc_i4_1_(VariantBase dummy) // \u0002\u2005\u2000 + { + var iv = new IntVariant(); + iv.SetValue(1); + PushVariant(iv); + } + + // Token: 0x0600022F RID: 559 RVA: 0x0000F8C8 File Offset: 0x0000DAC8 + private void Ldc_i4_2_(VariantBase dummy) // \u0005 + { + var iv = new IntVariant(); + iv.SetValue(2); + PushVariant(iv); + } + + // Token: 0x06000174 RID: 372 RVA: 0x00007BF4 File Offset: 0x00005DF4 + private void Ldc_i4_3_(VariantBase dummy) // \u0008\u2006\u2000 + { + var iv = new IntVariant(); + iv.SetValue(3); + PushVariant(iv); + } + + // Token: 0x06000262 RID: 610 RVA: 0x00010BEC File Offset: 0x0000EDEC + private void Ldc_i4_4_(VariantBase dummy) // \u000F\u2009\u2000 + { + var iv = new IntVariant(); + iv.SetValue(4); + PushVariant(iv); + } + + // Token: 0x060001B3 RID: 435 RVA: 0x000092B4 File Offset: 0x000074B4 + private void Ldc_i4_5_(VariantBase dummy) // \u0008\u2004\u2000 + { + var iv = new IntVariant(); + iv.SetValue(5); + PushVariant(iv); + } + + // Token: 0x06000231 RID: 561 RVA: 0x0000F900 File Offset: 0x0000DB00 + private void Ldc_i4_6_(VariantBase dummy) // \u0006\u2009\u2000 + { + var iv = new IntVariant(); + iv.SetValue(6); + PushVariant(iv); + } + + // Token: 0x0600026A RID: 618 RVA: 0x00010F88 File Offset: 0x0000F188 + private void Ldc_i4_7_(VariantBase dummy) // \u0003\u2003\u2000 + { + var iv = new IntVariant(); + iv.SetValue(7); + PushVariant(iv); + } + + // Token: 0x060001A9 RID: 425 RVA: 0x00008FA8 File Offset: 0x000071A8 + private void Ldc_i4_8_(VariantBase dummy) // \u000E\u2001 + { + var iv = new IntVariant(); + iv.SetValue(8); + PushVariant(iv); + } + + // Token: 0x0600016F RID: 367 RVA: 0x00007A58 File Offset: 0x00005C58 + private void Unbox_(VariantBase vTypeId) // \u0005\u2003\u2000 + { + var type = GetTypeById(((IntVariant)vTypeId).GetValue()); + var val = VariantFactory.Convert(PopVariant().GetValueAbstract(), type); + PushVariant(val); + } + + // Token: 0x06000207 RID: 519 RVA: 0x0000C228 File Offset: 0x0000A428 + private VmTokenInfo ReadVmToken(BinaryReader reader) // \u0002 + { + switch (reader.ReadByte()) + { + case (byte)VmTokenInfo.Kind.Class0: + { + var ret = new VmClassTokenInfo + { + OuterClassGenericMethodIdx = reader.ReadInt32(), + OuterClassGenericClassIdx = reader.ReadInt32(), + IsOuterClassGeneric = reader.ReadBoolean(), + ClassName = reader.ReadString(), + IsGeneric = reader.ReadBoolean(), + GenericArguments = new UniversalTokenInfo[(int) reader.ReadInt16()] + }; + for (var i = 0; i < ret.GenericArguments.Length; i++) + { + ret.GenericArguments[i] = new UniversalTokenInfo + { + IsVm = 1, + MetadataToken = reader.ReadInt32() + }; + } + return ret; + } + case (byte)VmTokenInfo.Kind.Field1: + return new VmFieldTokenInfo + { + Class = new UniversalTokenInfo + { + IsVm = 1, + MetadataToken = reader.ReadInt32() + }, + Name = reader.ReadString(), + IsStatic = reader.ReadBoolean() + }; + case (byte)VmTokenInfo.Kind.Method2: + { + var ret = new VmMethodTokenInfo + { + Class = new UniversalTokenInfo + { + IsVm = 1, + MetadataToken = reader.ReadInt32() + }, + Flags = reader.ReadByte(), + Name = reader.ReadString(), + ReturnType = new UniversalTokenInfo + { + IsVm = 1, + MetadataToken = reader.ReadInt32() + }, + Parameters = new UniversalTokenInfo[(int)reader.ReadInt16()] + }; + for (var j = 0; j < ret.Parameters.Length; j++) + { + ret.Parameters[j] = new UniversalTokenInfo + { + IsVm = 1, + MetadataToken = reader.ReadInt32() + }; + } + var gaCnt = (int)reader.ReadInt16(); + ret.GenericArguments = new UniversalTokenInfo[gaCnt]; + for (var k = 0; k < gaCnt; k++) + { + ret.GenericArguments[k] = new UniversalTokenInfo + { + IsVm = 1, + MetadataToken = reader.ReadInt32() + }; + } + return ret; + } + case (byte)VmTokenInfo.Kind.String3: + return new VmStringTokenInfo { Value = reader.ReadString() }; + case (byte)VmTokenInfo.Kind.MethodRef4: + return new VmMethodRefTokenInfo + { + Flags = reader.ReadInt32(), + Pos = reader.ReadInt32() + }; + default: + throw new ArgumentOutOfRangeException(); + } + } + + // Token: 0x06000175 RID: 373 RVA: 0x00007C08 File Offset: 0x00005E08 + private UniversalTokenInfo ReadToken(int pos) // u0002 + { + if (_srcVirtualizedStreamReader == null) + { + throw new InvalidOperationException(); + } + var baseStream = _srcVirtualizedStreamReader.BaseStream; + UniversalTokenInfo result; + lock (baseStream) + { + _srcVirtualizedStreamReader.BaseStream.Seek(pos, SeekOrigin.Begin); + result = new UniversalTokenInfo {IsVm = _srcVirtualizedStreamReader.ReadByte()}; + if (result.IsVm == 0) + { + result.MetadataToken = _srcVirtualizedStreamReader.ReadInt32(); + } + else + { + result.VmToken = ReadVmToken(_srcVirtualizedStreamReader); + } + } + return result; + } + + // Token: 0x06000248 RID: 584 RVA: 0x000102AC File Offset: 0x0000E4AC + private string Ldstr(int strToken) // \u0002 + { + string result; + lock (AllMetadataById) + { + object stored; + if (AllMetadataById.TryGetValue(strToken, out stored)) + { + result = (string)stored; + } + else + { + var tokenInfo = ReadToken(strToken); + if (tokenInfo.IsVm == 0) + { + result = _module.ResolveString(tokenInfo.MetadataToken); + } + else + { + var text = ((VmStringTokenInfo)tokenInfo.VmToken).Value; + AllMetadataById.Add(strToken, text); + result = text; + } + } + } + return result; + } + + // Token: 0x0600019C RID: 412 RVA: 0x00008B34 File Offset: 0x00006D34 + private void Ldstr_(VariantBase strToken) // \u000E\u2000\u2001 + { + var tok = ((IntVariant)strToken).GetValue(); + var text = Ldstr(tok); + var val = new StringVariant(); + val.SetValue(text); + PushVariant(val); + } + + // Token: 0x06000170 RID: 368 RVA: 0x00007A94 File Offset: 0x00005C94 + private VariantBase ReadOperand(MyBufferReader r, VmOperandType operandType) // \u0002 + { + switch (operandType) + { + case VmOperandType.Ot0UInt: + { + var ret = new UintVariant(); + ret.SetValue(r.ReadUint()); + return ret; + } + case VmOperandType.Ot1UShort: + case VmOperandType.Ot3UShort: + { + var ret = new UshortVariant(); + ret.SetValue(r.ReadUshort()); + return ret; + } + case VmOperandType.Ot2Byte: + case VmOperandType.Ot8Byte: + { + var ret = new ByteVariant(); + ret.SetValue(r.ReadByte()); + return ret; + } + case VmOperandType.Ot4Double: + { + var ret = new DoubleVariant(); + ret.SetValue(r.ReadDouble()); + return ret; + } + case VmOperandType.Ot5Int: + case VmOperandType.Ot12Int: + { + var ret = new IntVariant(); + ret.SetValue(r.ReadInt32()); + return ret; + } + case VmOperandType.Ot6SByte: + { + var ret = new SbyteVariant(); + ret.SetValue(r.ReadSbyte()); + return ret; + } + case VmOperandType.Ot7Long: + { + var ret = new LongVariant(); + ret.SetValue(r.ReadLong()); + return ret; + } + case VmOperandType.Ot9IntArr: + { + var num = r.ReadInt32(); + var array = new IntVariant[num]; + for (var i = 0; i < num; i++) + { + var item = new IntVariant(); + item.SetValue(r.ReadInt32()); + array[i] = item; + } + var ret = new ArrayVariant(); + ret.SetValue(array); + return ret; + } + case VmOperandType.Ot10Float: + { + var ret = new FloatVariant(); + ret.SetValue(r.ReadFloat()); + return ret; + } + case VmOperandType.Ot11Nope: + return null; + default: + throw new Exception(StringDecryptor.GetString(-1550347123) /* Unknown operand type. */); + } + } + + // Token: 0x06000279 RID: 633 RVA: 0x0001184C File Offset: 0x0000FA4C + enum ComparisonKind { EQ, NEQ, GT, LE, LT, GE } + private static bool UniCompare(VariantBase v1, VariantBase v2, ComparisonKind ck, bool unsignedNanBranch) // \u0008 - bug fixed (метод переписан) + { + // from stack: enum double single long int + var t1 = v1.GetTypeCode(); + if (t1 == VariantBase.Vtc.Tc5Enum) + { + var vv1 = VariantBase.SignedVariantFromEnum((EnumVariant)v1); + return UniCompare(vv1, v2, ck, unsignedNanBranch); + } + var t2 = v2.GetTypeCode(); + if (t2 == VariantBase.Vtc.Tc5Enum) + { + var vv2 = VariantBase.SignedVariantFromEnum((EnumVariant)v2); + return UniCompare(v1, vv2, ck, unsignedNanBranch); + } + if (t1 == VariantBase.Vtc.Tc18Object || t2 == VariantBase.Vtc.Tc18Object) + { + if (ck == ComparisonKind.EQ) return v1.GetValueAbstract().Equals(v2.GetValueAbstract()); + if (ck == ComparisonKind.NEQ) return !v1.GetValueAbstract().Equals(v2.GetValueAbstract()); + return false; + } + if (t1 == VariantBase.Vtc.Tc21Double || t2 == VariantBase.Vtc.Tc21Double) + { + var d1 = (t1 == VariantBase.Vtc.Tc21Double) ? ((DoubleVariant)v1).GetValue() : Convert.ToDouble(v1.GetValueAbstract()); + var d2 = (t2 == VariantBase.Vtc.Tc21Double) ? ((DoubleVariant)v2).GetValue() : Convert.ToDouble(v2.GetValueAbstract()); + if (unsignedNanBranch) unsignedNanBranch = (double.IsNaN(d1) || double.IsNaN(d2)); + switch (ck) + { + case ComparisonKind.EQ: + // ReSharper disable once CompareOfFloatsByEqualityOperator + return (d1 == d2) || unsignedNanBranch; + case ComparisonKind.GT: + return (d1 > d2) || unsignedNanBranch; + case ComparisonKind.NEQ: + // ReSharper disable once CompareOfFloatsByEqualityOperator + return (d1 != d2) || unsignedNanBranch; + case ComparisonKind.LE: + return (d1 <= d2) || unsignedNanBranch; + case ComparisonKind.LT: + return (d1 < d2) || unsignedNanBranch; + case ComparisonKind.GE: + return (d1 >= d2) || unsignedNanBranch; + } + } + if (t1 == VariantBase.Vtc.Tc8Float || t2 == VariantBase.Vtc.Tc8Float) + { + var d1 = (t1 == VariantBase.Vtc.Tc8Float) ? ((FloatVariant)v1).GetValue() : Convert.ToSingle(v1.GetValueAbstract()); + var d2 = (t2 == VariantBase.Vtc.Tc8Float) ? ((FloatVariant)v2).GetValue() : Convert.ToSingle(v2.GetValueAbstract()); + if (unsignedNanBranch) unsignedNanBranch = (float.IsNaN(d1) || float.IsNaN(d2)); + switch (ck) + { + case ComparisonKind.EQ: + // ReSharper disable once CompareOfFloatsByEqualityOperator + return (d1 == d2) || unsignedNanBranch; + case ComparisonKind.GT: + return (d1 > d2) || unsignedNanBranch; + case ComparisonKind.NEQ: + // ReSharper disable once CompareOfFloatsByEqualityOperator + return (d1 != d2) || unsignedNanBranch; + case ComparisonKind.LE: + return (d1 <= d2) || unsignedNanBranch; + case ComparisonKind.LT: + return (d1 < d2) || unsignedNanBranch; + case ComparisonKind.GE: + return (d1 >= d2) || unsignedNanBranch; + } + } + if (t1 == VariantBase.Vtc.Tc24Long || t2 == VariantBase.Vtc.Tc24Long) + { + var d1 = (t1 == VariantBase.Vtc.Tc24Long) ? ((LongVariant)v1).GetValue() : (unsignedNanBranch ? Convert.ToInt64((uint)(int)v1.GetValueAbstract()) : Convert.ToInt64(v1.GetValueAbstract())); + var d2 = (t2 == VariantBase.Vtc.Tc24Long) ? ((LongVariant)v2).GetValue() : (unsignedNanBranch ? Convert.ToInt64((uint)(int)v2.GetValueAbstract()) : Convert.ToInt64(v2.GetValueAbstract())); + switch (ck) + { + case ComparisonKind.EQ: + return d1 == d2; + case ComparisonKind.GT: + if(unsignedNanBranch) return (ulong)d1 > (ulong)d2; + return d1 > d2; + case ComparisonKind.NEQ: + if (unsignedNanBranch) return (ulong)d1 != (ulong)d2; + return d1 != d2; + case ComparisonKind.LE: + if (unsignedNanBranch) return (ulong)d1 <= (ulong)d2; + return d1 <= d2; + case ComparisonKind.LT: + if (unsignedNanBranch) return (ulong)d1 < (ulong)d2; + return d1 < d2; + case ComparisonKind.GE: + if (unsignedNanBranch) return (ulong)d1 >= (ulong)d2; + return d1 >= d2; + } + } + if (t1 == VariantBase.Vtc.Tc19Int || t2 == VariantBase.Vtc.Tc19Int) + { + switch (ck) + { + case ComparisonKind.EQ: + // ReSharper disable once CompareOfFloatsByEqualityOperator + return ((IntVariant)v1).GetValue() == ((IntVariant)v2).GetValue(); + case ComparisonKind.GT: + if (unsignedNanBranch) return (uint)((IntVariant)v1).GetValue() > (uint)((IntVariant)v2).GetValue(); + return ((IntVariant)v1).GetValue() > ((IntVariant)v2).GetValue(); + case ComparisonKind.NEQ: + if (unsignedNanBranch) return (uint)((IntVariant)v1).GetValue() != (uint)((IntVariant)v2).GetValue(); + return ((IntVariant)v1).GetValue() != ((IntVariant)v2).GetValue(); + case ComparisonKind.LE: + if (unsignedNanBranch) return (uint)((IntVariant)v1).GetValue() <= (uint)((IntVariant)v2).GetValue(); + return ((IntVariant)v1).GetValue() <= ((IntVariant)v2).GetValue(); + case ComparisonKind.LT: + if (unsignedNanBranch) return (uint)((IntVariant)v1).GetValue() < (uint)((IntVariant)v2).GetValue(); + return ((IntVariant)v1).GetValue() < ((IntVariant)v2).GetValue(); + //case ComparisonKind.GE: + default: + if (unsignedNanBranch) return (uint)((IntVariant)v1).GetValue() >= (uint)((IntVariant)v2).GetValue(); + return ((IntVariant)v1).GetValue() >= ((IntVariant)v2).GetValue(); + } + } + return false; + } + + // Token: 0x0600017F RID: 383 RVA: 0x00007EEC File Offset: 0x000060EC + private void Ldelema_(VariantBase vTypeId) // \u000F\u2002 + { + var type = GetTypeById(((IntVariant)vTypeId).GetValue()); + var idx = PopLong(); + var array = (Array)PopVariant().GetValueAbstract(); + var val = new SdArrayValueVariant(); + val.SetArray(array); + val.SetHeldType(type); + val.SetIndex(idx); + PushVariant(val); + } + + // Token: 0x06000252 RID: 594 RVA: 0x00010780 File Offset: 0x0000E980 + private void Ldelem_ref_(VariantBase dummy) // \u000F\u2003\u2000 + { + Ldelem(SimpleTypeHelper.ObjectType); + } + + // Token: 0x06000178 RID: 376 RVA: 0x00007D38 File Offset: 0x00005F38 + private static void SerializeCrossDomain(Exception ex) // \u0002 + { + if (ex == null) + { + return; + } + try + { + var type = ex.GetType(); + if (type.IsSerializable) + { + var context = new StreamingContext(StreamingContextStates.CrossAppDomain); + var om = new ObjectManager(null, context); + var info = new SerializationInfo(type, new FormatterConverter()); + ex.GetObjectData(info, context); + om.RegisterObject(ex, 1L, info); + om.DoFixups(); + } + } + catch + { + } + } + + // Token: 0x060001DF RID: 479 RVA: 0x0000ABCC File Offset: 0x00008DCC + private static void Throw(object ex) // \u0003 + { + throw (Exception)ex; + } + + // Token: 0x0600024D RID: 589 RVA: 0x000105A0 File Offset: 0x0000E7A0 + private static void ThrowStoreCrossDomain(object ex) // \u0002 + { + SerializeCrossDomain(ex as Exception); + Throw(ex); + } + + // Token: 0x06000293 RID: 659 RVA: 0x00012398 File Offset: 0x00010598 + private static VariantBase SubLong(VariantBase v1, VariantBase v2, bool bChecked, bool bUnsigned) // \u0005 + { + var lvret = new LongVariant(); + if (!bUnsigned) + { + var l1 = ((LongVariant)v1).GetValue(); + var l2 = ((LongVariant)v2).GetValue(); + long lret; + if (bChecked) + { + lret = checked(l1 - l2); + } + else + { + lret = l1 - l2; + } + lvret.SetValue(lret); + return lvret; + } + var u1 = (ulong)((LongVariant)v1).GetValue(); + var u2 = (ulong)((LongVariant)v2).GetValue(); + ulong uret; + if (bChecked) + { + uret = checked(u1 - u2); + } + else + { + uret = u1 - u2; + } + lvret.SetValue((long)uret); + return lvret; + } + + private VariantBase Sub(bool ovf, bool signed) + { + VariantBase v1, v2; + var org_v2 = PopVariant(); + var org_v1 = PopVariant(); + var tc = CommonType(org_v1, org_v2, out v1, out v2, signed); + VariantBase ret; + switch (tc) + { + case VariantBase.Vtc.Tc9Uint: + uint uv1 = ((UintVariant)v1).GetValue(), uv2 = ((UintVariant)v2).GetValue(); + var uvret = new UintVariant(); + ret = uvret; + if (ovf) + { + uint uiv; + checked + { + uiv = uv1 - uv2; + } + uvret.SetValue(uiv); + } + else + { + uvret.SetValue(uv1 - uv2); + } + break; + case VariantBase.Vtc.Tc19Int: + int iv1 = ((IntVariant)v1).GetValue(), iv2 = ((IntVariant)v2).GetValue(); + var ivret = new IntVariant(); + ret = ivret; + if (ovf) + { + checked + { + ivret.SetValue(iv1 - iv2); + } + } + else + { + ivret.SetValue(iv1 - iv2); + } + break; + case VariantBase.Vtc.Tc21Double: + double dv1 = ((DoubleVariant)v1).GetValue(), dv2 = ((DoubleVariant)v2).GetValue(); + var dvret = new DoubleVariant(); + ret = dvret; + dvret.SetValue(dv1 - dv2); + break; + case VariantBase.Vtc.Tc8Float: + float fv1 = ((FloatVariant)v1).GetValue(), fv2 = ((FloatVariant)v2).GetValue(); + var fvret = new FloatVariant(); + ret = fvret; + fvret.SetValue(fv1 - fv2); + break; + case VariantBase.Vtc.Tc24Long: + long lv1 = ((LongVariant)v1).GetValue(), lv2 = ((LongVariant)v2).GetValue(); + var lvret = new LongVariant(); + ret = lvret; + if (ovf) + { + checked + { + lvret.SetValue(lv1 - lv2); + } + } + else + { + lvret.SetValue(lv1 - lv2); + } + break; + case VariantBase.Vtc.Tc7Ulong: + ulong ulv1 = ((UlongVariant)v1).GetValue(), ulv2 = ((UlongVariant)v2).GetValue(); + var ulvret = new UlongVariant(); + ret = ulvret; + if (ovf) + { + ulong ulv; + checked + { + ulv = ulv1 - ulv2; + } + ulvret.SetValue(ulv); + } + else + { + ulvret.SetValue(ulv1 - ulv2); + } + break; + default: + // это нужно будет заменить на соотв. msil-код + var dyn = new DynamicMethod(String.Empty, typeof(IntPtr), new[] { typeof(object), typeof(object) }, typeof(void), true); + var gen = dyn.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_1); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(signed ? (ovf ? OpCodes.Sub_Ovf : OpCodes.Sub) : OpCodes.Sub_Ovf_Un); + gen.Emit(OpCodes.Ret); + ret = new IntPtrVariant(); + ((IntPtrVariant)ret).SetValue(((IntPtr)dyn.Invoke(null, new[] { org_v1.GetValueAbstract(), org_v2.GetValueAbstract() }))); + break; + } + return ret; + } + + // Token: 0x0600026B RID: 619 RVA: 0x00010F9C File Offset: 0x0000F19C + private void Sub_ovf_un_(VariantBase dummy) // \u0005\u2006\u2000 + { + PushVariant(Sub(true, false)); + } + + // Token: 0x060001A8 RID: 424 RVA: 0x00008F7C File Offset: 0x0000717C + private void Sub_ovf_(VariantBase dummy) // \u0005\u2008 + { + PushVariant(Sub(true, true)); + } + + // Token: 0x0600021C RID: 540 RVA: 0x0000C84C File Offset: 0x0000AA4C + private void Sub_(VariantBase dummy) // \u0006\u200A + { + PushVariant(Sub(false, true)); + } + + // Token: 0x06000271 RID: 625 RVA: 0x00011144 File Offset: 0x0000F344 + private static VariantBase MulLong(VariantBase v1, VariantBase v2, bool bChecked, bool bUnsigned) // \u0003 + { + var lvret = new LongVariant(); + if (!bUnsigned) + { + var l1 = ((LongVariant)v1).GetValue(); + var l2 = ((LongVariant)v2).GetValue(); + long lret; + if (bChecked) + { + lret = checked(l1 * l2); + } + else + { + lret = l1 * l2; + } + lvret.SetValue(lret); + return lvret; + } + var u1 = (ulong)((LongVariant)v1).GetValue(); + var u2 = (ulong)((LongVariant)v2).GetValue(); + ulong uret; + if (bChecked) + { + uret = checked(u1 * u2); + } + else + { + uret = u1 * u2; + } + lvret.SetValue((long)uret); + return lvret; + } + + private VariantBase Mul(bool ovf, bool signed) + { + VariantBase v1, v2; + var org_v2 = PopVariant(); + var org_v1 = PopVariant(); + var tc = CommonType(org_v1, org_v2, out v1, out v2, signed); + VariantBase ret; + switch (tc) + { + case VariantBase.Vtc.Tc9Uint: + uint uv1 = ((UintVariant)v1).GetValue(), uv2 = ((UintVariant)v2).GetValue(); + var uvret = new UintVariant(); + ret = uvret; + if (ovf) + { + uint uiv; + checked + { + uiv = uv1 * uv2; + } + uvret.SetValue(uiv); + } + else + { + uvret.SetValue(uv1 * uv2); + } + break; + case VariantBase.Vtc.Tc19Int: + int iv1 = ((IntVariant)v1).GetValue(), iv2 = ((IntVariant)v2).GetValue(); + var ivret = new IntVariant(); + ret = ivret; + if (ovf) + { + checked + { + ivret.SetValue(iv1 * iv2); + } + } + else + { + ivret.SetValue(iv1 * iv2); + } + break; + case VariantBase.Vtc.Tc21Double: + double dv1 = ((DoubleVariant)v1).GetValue(), dv2 = ((DoubleVariant)v2).GetValue(); + var dvret = new DoubleVariant(); + ret = dvret; + dvret.SetValue(dv1 * dv2); + break; + case VariantBase.Vtc.Tc8Float: + float fv1 = ((FloatVariant)v1).GetValue(), fv2 = ((FloatVariant)v2).GetValue(); + var fvret = new FloatVariant(); + ret = fvret; + fvret.SetValue(fv1 * fv2); + break; + case VariantBase.Vtc.Tc24Long: + long lv1 = ((LongVariant)v1).GetValue(), lv2 = ((LongVariant)v2).GetValue(); + var lvret = new LongVariant(); + ret = lvret; + if (ovf) + { + checked + { + lvret.SetValue(lv1 * lv2); + } + } + else + { + lvret.SetValue(lv1 * lv2); + } + break; + case VariantBase.Vtc.Tc7Ulong: + ulong ulv1 = ((UlongVariant)v1).GetValue(), ulv2 = ((UlongVariant)v2).GetValue(); + var ulvret = new UlongVariant(); + ret = ulvret; + if (ovf) + { + ulong ulv; + checked + { + ulv = ulv1 * ulv2; + } + ulvret.SetValue(ulv); + } + else + { + ulvret.SetValue(ulv1 * ulv2); + } + break; + default: + // это нужно будет заменить на соотв. msil-код + var dyn = new DynamicMethod(String.Empty, typeof(IntPtr), new[] { typeof(object), typeof(object) }, typeof(void), true); + var gen = dyn.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_1); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(signed ? (ovf ? OpCodes.Mul_Ovf : OpCodes.Mul) : OpCodes.Mul_Ovf_Un); + gen.Emit(OpCodes.Ret); + ret = new IntPtrVariant(); + ((IntPtrVariant)ret).SetValue(((IntPtr)dyn.Invoke(null, new[] { org_v1.GetValueAbstract(), org_v2.GetValueAbstract() }))); + break; + } + return ret; + } + + // Token: 0x06000181 RID: 385 RVA: 0x00007F88 File Offset: 0x00006188 + private void Mul_ovf_un_(VariantBase dummy) // \u0005\u2007 + { + PushVariant(Mul(true, false)); + } + + // Token: 0x060001E1 RID: 481 RVA: 0x0000ABDC File Offset: 0x00008DDC + private void Mul_(VariantBase dummy) // \u0006\u2001\u2001 + { + PushVariant(Mul(false, true)); + } + + // Token: 0x060001A0 RID: 416 RVA: 0x00008C98 File Offset: 0x00006E98 + private void Mul_ovf_(VariantBase dummy) // \u0008\u2000\u2000 + { + PushVariant(Mul(true, true)); + } + + VariantBase.Vtc CommonType(VariantBase org_v1, VariantBase org_v2, out VariantBase v1, out VariantBase v2, bool signed) + { + v1 = org_v1.Clone(); + v2 = org_v2.Clone(); + var tc1 = UnderlyingTypeCode(ref v1); + var tc2 = UnderlyingTypeCode(ref v2); + if (tc1 == VariantBase.Vtc.Tc18Object || tc2 == VariantBase.Vtc.Tc18Object) + return VariantBase.Vtc.Tc18Object; + VariantBase.Vtc ret = tc1; + if (!signed) + { + v1 = AsUnsigned(v1); + v2 = AsUnsigned(v2); + } + if(tc1 != tc2) switch (tc1) + { + case VariantBase.Vtc.Tc19Int: + switch (tc2) + { + case VariantBase.Vtc.Tc24Long: + { + ret = tc2; + var new_v1 = signed ? (VariantBase)new LongVariant() : new UlongVariant(); + new_v1.CopyFrom(v1); + v1 = new_v1; + } + break; + case VariantBase.Vtc.Tc21Double: + { + ret = tc2; + var new_v1 = new DoubleVariant(); + new_v1.CopyFrom(v1); + v1 = new_v1; + } + break; + case VariantBase.Vtc.Tc8Float: + { + ret = tc2; + var new_v1 = new FloatVariant(); + new_v1.CopyFrom(v1); + v1 = new_v1; + } + break; + } + break; + case VariantBase.Vtc.Tc24Long: + switch (tc2) + { + case VariantBase.Vtc.Tc19Int: + { + var new_v2 = signed ? (VariantBase)new LongVariant() : new UlongVariant(); + new_v2.CopyFrom(v2); + v2 = new_v2; + } + break; + case VariantBase.Vtc.Tc21Double: + { + ret = tc2; + var new_v1 = new DoubleVariant(); + new_v1.CopyFrom(v1); + v1 = new_v1; + } + break; + case VariantBase.Vtc.Tc8Float: + { + ret = tc2; + var new_v1 = new FloatVariant(); + new_v1.CopyFrom(v1); + v1 = new_v1; + } + break; + } + break; + case VariantBase.Vtc.Tc21Double: + switch (tc2) + { + case VariantBase.Vtc.Tc19Int: + case VariantBase.Vtc.Tc24Long: + case VariantBase.Vtc.Tc8Float: + { + var new_v2 = new DoubleVariant(); + new_v2.CopyFrom(v2); + v2 = new_v2; + } + break; + } + break; + case VariantBase.Vtc.Tc8Float: + switch (tc2) + { + case VariantBase.Vtc.Tc19Int: + case VariantBase.Vtc.Tc24Long: + { + var new_v2 = new FloatVariant(); + new_v2.CopyFrom(v2); + v2 = new_v2; + } + break; + case VariantBase.Vtc.Tc21Double: + { + ret = tc2; + var new_v1 = new DoubleVariant(); + new_v1.CopyFrom(v1); + v1 = new_v1; + } + break; + } + break; + } + if(!signed) switch (ret) + { + case VariantBase.Vtc.Tc19Int: + return VariantBase.Vtc.Tc9Uint; + case VariantBase.Vtc.Tc24Long: + return VariantBase.Vtc.Tc7Ulong; + } + return ret; + } + + private VariantBase.Vtc UnderlyingTypeCode(ref VariantBase v) + { + var ret = v.GetTypeCode(); + if (ret == VariantBase.Vtc.Tc5Enum) + { + v = VariantBase.SignedVariantFromEnum((EnumVariant) v); + ret = Marshal.SizeOf(v.GetValueAbstract()) == 4 ? VariantBase.Vtc.Tc19Int : VariantBase.Vtc.Tc24Long; + } + return ret; + } + + private VariantBase AsUnsigned(VariantBase v) + { + var tc = v.GetTypeCode(); + var ret = v; + switch (tc) + { + case VariantBase.Vtc.Tc19Int: + ret = new UintVariant(); + break; + case VariantBase.Vtc.Tc24Long: + ret = new UlongVariant(); + break; + } + ret.CopyFrom(v); + return ret; + } + + private VariantBase Add(bool ovf, bool signed) + { + VariantBase v1, v2; + var org_v2 = PopVariant(); + var org_v1 = PopVariant(); + var tc = CommonType(org_v1, org_v2, out v1, out v2, signed); + VariantBase ret; + switch (tc) + { + case VariantBase.Vtc.Tc9Uint: + uint uv1 = ((UintVariant)v1).GetValue(), uv2 = ((UintVariant)v2).GetValue(); + var uvret = new UintVariant(); + ret = uvret; + if (ovf) + { + uint uiv; + checked + { + uiv = uv1 + uv2; + } + uvret.SetValue(uiv); + } + else + { + uvret.SetValue(uv1 + uv2); + } + break; + case VariantBase.Vtc.Tc19Int: + int iv1 = ((IntVariant)v1).GetValue(), iv2 = ((IntVariant)v2).GetValue(); + var ivret = new IntVariant(); + ret = ivret; + if (ovf) + { + checked + { + ivret.SetValue(iv1 + iv2); + } + } + else + { + ivret.SetValue(iv1 + iv2); + } + break; + case VariantBase.Vtc.Tc21Double: + double dv1 = ((DoubleVariant)v1).GetValue(), dv2 = ((DoubleVariant)v2).GetValue(); + var dvret = new DoubleVariant(); + ret = dvret; + dvret.SetValue(dv1 + dv2); + break; + case VariantBase.Vtc.Tc8Float: + float fv1 = ((FloatVariant)v1).GetValue(), fv2 = ((FloatVariant)v2).GetValue(); + var fvret = new FloatVariant(); + ret = fvret; + fvret.SetValue(fv1 + fv2); + break; + case VariantBase.Vtc.Tc24Long: + long lv1 = ((LongVariant)v1).GetValue(), lv2 = ((LongVariant)v2).GetValue(); + var lvret = new LongVariant(); + ret = lvret; + if (ovf) + { + checked + { + lvret.SetValue(lv1 + lv2); + } + } + else + { + lvret.SetValue(lv1 + lv2); + } + break; + case VariantBase.Vtc.Tc7Ulong: + ulong ulv1 = ((UlongVariant)v1).GetValue(), ulv2 = ((UlongVariant)v2).GetValue(); + var ulvret = new UlongVariant(); + ret = ulvret; + if (ovf) + { + ulong ulv; + checked + { + ulv = ulv1 + ulv2; + } + ulvret.SetValue(ulv); + } + else + { + ulvret.SetValue(ulv1 + ulv2); + } + break; + default: + // это нужно будет заменить на соотв. msil-код + var dyn = new DynamicMethod(String.Empty, typeof(IntPtr), new[] { typeof(object), typeof(object) }, typeof(void), true); + var gen = dyn.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_1); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(signed ? (ovf ? OpCodes.Add_Ovf : OpCodes.Add) : OpCodes.Add_Ovf_Un); + gen.Emit(OpCodes.Ret); + ret = new IntPtrVariant(); + ((IntPtrVariant)ret).SetValue(((IntPtr)dyn.Invoke(null, new[] { org_v1.GetValueAbstract(), org_v2.GetValueAbstract() }))); + break; + } + return ret; + } + + // Token: 0x0600022D RID: 557 RVA: 0x0000F880 File Offset: 0x0000DA80 + private void Add_ovf_(VariantBase dummy) // \u0008\u2001 + { + PushVariant(Add(true, true)); + } + + // Token: 0x06000238 RID: 568 RVA: 0x0000F998 File Offset: 0x0000DB98 + private void Add_(VariantBase dummy) // \u0002\u2004 + { + PushVariant(Add(false, true)); + } + + // Token: 0x0600029B RID: 667 RVA: 0x000126A0 File Offset: 0x000108A0 + private void Add_ovf_un_(VariantBase dummy) // \u0002\u2004\u2000 + { + PushVariant(Add(true, false)); + } + + private VariantBase Or(VariantBase org_v1, VariantBase org_v2) + { + VariantBase v1, v2; + var tc = CommonType(org_v1, org_v2, out v1, out v2, true); + VariantBase ret; + switch (tc) + { + case VariantBase.Vtc.Tc9Uint: + uint uv1 = ((UintVariant)v1).GetValue(), uv2 = ((UintVariant)v2).GetValue(); + var uvret = new UintVariant(); + ret = uvret; + uvret.SetValue(uv1 | uv2); + break; + case VariantBase.Vtc.Tc19Int: + int iv1 = ((IntVariant)v1).GetValue(), iv2 = ((IntVariant)v2).GetValue(); + var ivret = new IntVariant(); + ret = ivret; + ivret.SetValue(iv1 | iv2); + break; + case VariantBase.Vtc.Tc21Double: + { + /*double dv1 = ((DoubleVariant)v1).GetValue(), dv2 = ((DoubleVariant)v2).GetValue(); // естественный алгоритм + long lv1 = (dv1 < 0) ? (long)dv1 : (long)(ulong)dv1; + long lv2 = (dv2 < 0) ? (long)dv2 : (long)(ulong)dv2; + var dvret = new DoubleVariant(); + ret = dvret; + var l64 = (ulong) lv1 | (ulong) lv2; + if (l64 >> 32 == UInt32.MaxValue) l64 &= UInt32.MaxValue; + dvret.SetValue(l64);*/ + var dvret = new DoubleVariant(); + ret = dvret; + dvret.SetValue((4 == IntPtr.Size) ? Double.NaN : (double)0); // иногда у фреймворка бывает мусор, но чаще эти значения... + } + break; + case VariantBase.Vtc.Tc8Float: + { + /*float fv1 = ((FloatVariant) v1).GetValue(), fv2 = ((FloatVariant) v2).GetValue(); // естественный алгоритм + long lv1 = (fv1 < 0) ? (long)fv1 : (long)(ulong)fv1; + long lv2 = (fv2 < 0) ? (long)fv2 : (long)(ulong)fv2; + var fvret = new FloatVariant(); + ret = fvret; + var l64 = (ulong)lv1 | (ulong)lv2; + if (l64 >> 32 == UInt32.MaxValue) l64 &= UInt32.MaxValue; + fvret.SetValue(l64);*/ + var fvret = new FloatVariant(); + ret = fvret; + fvret.SetValue((4 == IntPtr.Size) ? float.NaN : (float)0.0); // иногда у фреймворка бывает мусор, но чаще эти значения... + } + break; + case VariantBase.Vtc.Tc24Long: + { + long lv1 = ((LongVariant)v1).GetValue(), lv2 = ((LongVariant)v2).GetValue(); + var lvret = new LongVariant(); + ret = lvret; + lvret.SetValue(lv1 | lv2); + } + break; + case VariantBase.Vtc.Tc7Ulong: + ulong ulv1 = ((UlongVariant)v1).GetValue(), ulv2 = ((UlongVariant)v2).GetValue(); + var ulvret = new UlongVariant(); + ret = ulvret; + ulvret.SetValue(ulv1 | ulv2); + break; + default: + // это нужно будет заменить на соотв. msil-код + var dyn = new DynamicMethod(String.Empty, typeof(IntPtr), new[] { typeof(object), typeof(object) }, typeof(void), true); + var gen = dyn.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_1); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(OpCodes.Or); + gen.Emit(OpCodes.Ret); + ret = new IntPtrVariant(); + ((IntPtrVariant)ret).SetValue(((IntPtr)dyn.Invoke(null, new[] { org_v1.GetValueAbstract(), org_v2.GetValueAbstract() }))); + break; + } + return ret; + } + + // Token: 0x0600020F RID: 527 RVA: 0x0000C598 File Offset: 0x0000A798 + private void Or_(VariantBase dummy) // \u0006\u2002\u2000 + { + var v2 = PopVariant(); + var v1 = PopVariant(); + PushVariant(Or(v1, v2)); + } + + // Token: 0x060001D8 RID: 472 RVA: 0x0000A718 File Offset: 0x00008918 + private void Throw_(VariantBase dummy) // \u0006\u2005\u2000 + { + ThrowStoreCrossDomain(PopVariant().GetValueAbstract()); + } + + private VariantBase Rem(bool signed) + { + VariantBase v1, v2; + var org_v2 = PopVariant(); + var org_v1 = PopVariant(); + VariantBase ret; + var tc = CommonType(org_v1, org_v2, out v1, out v2, signed); + if (IsFloating(org_v1) && org_v1.GetType() == org_v2.GetType() && !signed) + { + if (IntPtr.Size == 8) throw new InvalidProgramException(); + if (tc == VariantBase.Vtc.Tc21Double) + { + ret = new DoubleVariant(); + ret.SetValueAbstract(double.NaN); + } + else /*if (tc == VariantBase.Vtc.Tc8Float)*/ + { + ret = new FloatVariant(); + ret.SetValueAbstract(float.NaN); + } + } + else switch (tc) + { + case VariantBase.Vtc.Tc9Uint: + uint uv1 = ((UintVariant)v1).GetValue(), uv2 = ((UintVariant)v2).GetValue(); + var uvret = new UintVariant(); + ret = uvret; + uvret.SetValue(uv1 % uv2); + break; + case VariantBase.Vtc.Tc19Int: + int iv1 = ((IntVariant)v1).GetValue(), iv2 = ((IntVariant)v2).GetValue(); + var ivret = new IntVariant(); + ret = ivret; + ivret.SetValue(iv1 % iv2); + break; + case VariantBase.Vtc.Tc21Double: + double dv1 = ((DoubleVariant)v1).GetValue(), dv2 = ((DoubleVariant)v2).GetValue(); + var dvret = new DoubleVariant(); + ret = dvret; + if (Math.Abs(dv2) < double.Epsilon && org_v1.GetType() != org_v2.GetType()) throw new DivideByZeroException(); + dvret.SetValue(dv1 % dv2); + break; + case VariantBase.Vtc.Tc8Float: + float fv1 = ((FloatVariant)v1).GetValue(), fv2 = ((FloatVariant)v2).GetValue(); + var fvret = new FloatVariant(); + ret = fvret; + if (Math.Abs(fv2) < float.Epsilon && org_v1.GetType() != org_v2.GetType()) throw new DivideByZeroException(); + fvret.SetValue(fv1 % fv2); + break; + case VariantBase.Vtc.Tc24Long: + long lv1 = ((LongVariant)v1).GetValue(), lv2 = ((LongVariant)v2).GetValue(); + var lvret = new LongVariant(); + ret = lvret; + lvret.SetValue(lv1 % lv2); + break; + case VariantBase.Vtc.Tc7Ulong: + ulong ulv1 = ((UlongVariant)v1).GetValue(), ulv2 = ((UlongVariant)v2).GetValue(); + var ulvret = new UlongVariant(); + ret = ulvret; + ulvret.SetValue(ulv1 % ulv2); + break; + default: + // это нужно будет заменить на соотв. msil-код + var dyn = new DynamicMethod(String.Empty, typeof(IntPtr), new[] { typeof(object), typeof(object) }, typeof(void), true); + var gen = dyn.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_1); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(signed ? OpCodes.Rem : OpCodes.Rem_Un); + gen.Emit(OpCodes.Ret); + ret = new IntPtrVariant(); + ((IntPtrVariant)ret).SetValue(((IntPtr)dyn.Invoke(null, new[] { org_v1.GetValueAbstract(), org_v2.GetValueAbstract() }))); + break; + } + return ret; + } + + // Token: 0x060001CC RID: 460 RVA: 0x00009EAC File Offset: 0x000080AC + private void Rem_(VariantBase dummy) // \u0006\u2000\u2001 + { + PushVariant(Rem(true)); + } + + // Token: 0x060001FA RID: 506 RVA: 0x0000BC3C File Offset: 0x00009E3C + private void Rem_un_(VariantBase dummy) // \u0006\u200B\u2000 + { + PushVariant(Rem(false)); + } + + // Token: 0x06000254 RID: 596 RVA: 0x00010824 File Offset: 0x0000EA24 + private static VariantBase Neg(VariantBase v) // \u0002 + { + if (v.GetTypeCode() == VariantBase.Vtc.Tc19Int) + { + var i = ((IntVariant)v).GetValue(); + var ivret = new IntVariant(); + ivret.SetValue(-i); + return ivret; + } + if (v.GetTypeCode() == VariantBase.Vtc.Tc24Long) + { + var l = ((LongVariant)v).GetValue(); + var lvret = new LongVariant(); + lvret.SetValue(-l); + return lvret; + } + if (v.GetTypeCode() == VariantBase.Vtc.Tc21Double) + { + var dvret = new DoubleVariant(); + dvret.SetValue(-((DoubleVariant)v).GetValue()); + return dvret; + } + if (v.GetTypeCode() != VariantBase.Vtc.Tc5Enum) + { + throw new InvalidOperationException(); + } + var underlyingType = Enum.GetUnderlyingType(v.GetValueAbstract().GetType()); + if (underlyingType == typeof(long) || underlyingType == typeof(ulong)) + { + var lvret = new LongVariant(); + lvret.SetValue(Convert.ToInt64(v.GetValueAbstract())); + return Neg(lvret); + } + var ivret2 = new IntVariant(); + ivret2.SetValue(Convert.ToInt32(v.GetValueAbstract())); + return Neg(ivret2); + } + + // Token: 0x060001F8 RID: 504 RVA: 0x0000BA00 File Offset: 0x00009C00 + private void Neg_(VariantBase dummy) // \u0006\u2007 + { + var v = PopVariant(); + PushVariant(Neg(v)); + } + + // Token: 0x06000242 RID: 578 RVA: 0x0000FE38 File Offset: 0x0000E038 + private static VariantBase DivLong(VariantBase v1, VariantBase v2, bool bUnsigned) // \u0003 + { + var lvret = new LongVariant(); + if (!bUnsigned) + { + var l1 = ((LongVariant)v1).GetValue(); + var l2 = ((LongVariant)v2).GetValue(); + lvret.SetValue(l1 / l2); + return lvret; + } + var u1 = (ulong)((LongVariant)v1).GetValue(); + var u2 = (ulong)((LongVariant)v2).GetValue(); + lvret.SetValue((long)(u1 / u2)); + return lvret; + } + + private VariantBase Div(bool signed) + { + VariantBase v1, v2; + var org_v2 = PopVariant(); + var org_v1 = PopVariant(); + VariantBase ret; + var tc = CommonType(org_v1, org_v2, out v1, out v2, signed); + if (IsFloating(org_v1) && org_v1.GetType() == org_v2.GetType() && !signed) + { + if (IntPtr.Size == 8) throw new InvalidProgramException(); + if(tc == VariantBase.Vtc.Tc21Double) + { + ret = new DoubleVariant(); + ret.SetValueAbstract(double.NaN); + } else /*if (tc == VariantBase.Vtc.Tc8Float)*/ + { + ret = new FloatVariant(); + ret.SetValueAbstract(float.NaN); + } + } else switch (tc) + { + case VariantBase.Vtc.Tc9Uint: + uint uv1 = ((UintVariant)v1).GetValue(), uv2 = ((UintVariant)v2).GetValue(); + var uvret = new UintVariant(); + ret = uvret; + uvret.SetValue(uv1 / uv2); + break; + case VariantBase.Vtc.Tc19Int: + int iv1 = ((IntVariant)v1).GetValue(), iv2 = ((IntVariant)v2).GetValue(); + var ivret = new IntVariant(); + ret = ivret; + ivret.SetValue(iv1 / iv2); + break; + case VariantBase.Vtc.Tc21Double: + double dv1 = ((DoubleVariant)v1).GetValue(), dv2 = ((DoubleVariant)v2).GetValue(); + var dvret = new DoubleVariant(); + ret = dvret; + if(Math.Abs(dv2) < double.Epsilon && org_v1.GetType() != org_v2.GetType()) throw new DivideByZeroException(); + dvret.SetValue(dv1 / dv2); + break; + case VariantBase.Vtc.Tc8Float: + float fv1 = ((FloatVariant)v1).GetValue(), fv2 = ((FloatVariant)v2).GetValue(); + var fvret = new FloatVariant(); + ret = fvret; + if (Math.Abs(fv2) < float.Epsilon && org_v1.GetType() != org_v2.GetType()) throw new DivideByZeroException(); + fvret.SetValue(fv1 / fv2); + break; + case VariantBase.Vtc.Tc24Long: + long lv1 = ((LongVariant)v1).GetValue(), lv2 = ((LongVariant)v2).GetValue(); + var lvret = new LongVariant(); + ret = lvret; + lvret.SetValue(lv1 / lv2); + break; + case VariantBase.Vtc.Tc7Ulong: + ulong ulv1 = ((UlongVariant)v1).GetValue(), ulv2 = ((UlongVariant)v2).GetValue(); + var ulvret = new UlongVariant(); + ret = ulvret; + ulvret.SetValue(ulv1 / ulv2); + break; + default: + // это нужно будет заменить на соотв. msil-код + var dyn = new DynamicMethod(String.Empty, typeof(IntPtr), new[] { typeof(object), typeof(object) }, typeof(void), true); + var gen = dyn.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_1); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(signed ? OpCodes.Div : OpCodes.Div_Un); + gen.Emit(OpCodes.Ret); + ret = new IntPtrVariant(); + ((IntPtrVariant)ret).SetValue(((IntPtr)dyn.Invoke(null, new[] { org_v1.GetValueAbstract(), org_v2.GetValueAbstract() }))); + break; + } + return ret; + } + + // Token: 0x060001F0 RID: 496 RVA: 0x0000B664 File Offset: 0x00009864 + private void Div_(VariantBase dummy) // \u0002\u2009 + { + PushVariant(Div(true)); + } + + // Token: 0x0600017C RID: 380 RVA: 0x00007DF4 File Offset: 0x00005FF4 + private void Div_un_(VariantBase dummy) // \u000E\u200B + { + PushVariant(Div(false)); + } + + // Token: 0x0600026D RID: 621 RVA: 0x00010FF4 File Offset: 0x0000F1F4 + private static void EmitLdc(ILGenerator gen, int val) // \u0002 + { + switch (val) + { + case -1: + gen.Emit(OpCodes.Ldc_I4_M1); + return; + case 0: + gen.Emit(OpCodes.Ldc_I4_0); + return; + case 1: + gen.Emit(OpCodes.Ldc_I4_1); + return; + case 2: + gen.Emit(OpCodes.Ldc_I4_2); + return; + case 3: + gen.Emit(OpCodes.Ldc_I4_3); + return; + case 4: + gen.Emit(OpCodes.Ldc_I4_4); + return; + case 5: + gen.Emit(OpCodes.Ldc_I4_5); + return; + case 6: + gen.Emit(OpCodes.Ldc_I4_6); + return; + case 7: + gen.Emit(OpCodes.Ldc_I4_7); + return; + case 8: + gen.Emit(OpCodes.Ldc_I4_8); + return; + default: + if (val > -129 && val < 128) + { + gen.Emit(OpCodes.Ldc_I4_S, (sbyte)val); + return; + } + gen.Emit(OpCodes.Ldc_I4, val); + return; + } + } + + // Token: 0x06000264 RID: 612 RVA: 0x00010C28 File Offset: 0x0000EE28 + private static void EnsureClass(ILGenerator gen, Type t) // \u0003 + { + if (t == SimpleTypeHelper.ObjectType) + { + return; + } + gen.Emit(OpCodes.Castclass, t); + } + + // Token: 0x06000277 RID: 631 RVA: 0x0001180C File Offset: 0x0000FA0C + private static void EnsureType(ILGenerator gen, Type t) // \u0005 + { + if (t.IsValueType || ElementedTypeHelper.TryGoToElementType(t).IsGenericParameter) + { + gen.Emit(OpCodes.Unbox_Any, t); + return; + } + EnsureClass(gen, t); + } + + // Token: 0x06000217 RID: 535 RVA: 0x0000C7EC File Offset: 0x0000A9EC + private static void EnsureBoxed(ILGenerator gen, Type t) // \u0002 + { + if (t.IsValueType || ElementedTypeHelper.TryGoToElementType(t).IsGenericParameter) + { + gen.Emit(OpCodes.Box, t); + } + } + + // Token: 0x0600023E RID: 574 RVA: 0x0000FA54 File Offset: 0x0000DC54 + private DynamicExecutor DynamicFor(MethodBase mb, bool mayVirtual) // \u0002 + { + DynamicMethod dynamicMethod; /*= null; + if (_alwaysFalse && (!mb.IsConstructor || !typeof(Delegate).IsAssignableFrom(mb.DeclaringType))) + { + dynamicMethod = new DynamicMethod(string.Empty, SimpleTypeHelper.ObjectType, new Type[] + { + SimpleTypeHelper.ObjectType, + ObjectArrayType + }, true); + } + if (dynamicMethod == null)*/ + { + dynamicMethod = new DynamicMethod(string.Empty, SimpleTypeHelper.ObjectType, new[] + { + SimpleTypeHelper.ObjectType, + ObjectArrayType + }, typeof(VmExecutor).Module, true); + } + var iLGenerator = dynamicMethod.GetILGenerator(); + var parameters = mb.GetParameters(); + var array = new Type[parameters.Length]; + var flag = false; + for (var i = 0; i < parameters.Length; i++) + { + var type = parameters[i].ParameterType; + if (type.IsByRef) + { + flag = true; + type = type.GetElementType(); + } + array[i] = type; + } + var array2 = new LocalBuilder[array.Length]; + if (array2.Length != 0) + { + dynamicMethod.InitLocals = true; + } + for (var j = 0; j < array.Length; j++) + { + array2[j] = iLGenerator.DeclareLocal(array[j]); + } + for (var k = 0; k < array.Length; k++) + { + iLGenerator.Emit(OpCodes.Ldarg_1); + EmitLdc(iLGenerator, k); + iLGenerator.Emit(OpCodes.Ldelem_Ref); + EnsureType(iLGenerator, array[k]); + iLGenerator.Emit(OpCodes.Stloc, array2[k]); + } + if (flag) + { + iLGenerator.BeginExceptionBlock(); + } + if (!mb.IsStatic && !mb.IsConstructor) + { + iLGenerator.Emit(OpCodes.Ldarg_0); + var declaringType = mb.DeclaringType; + if (declaringType.IsValueType) + { + iLGenerator.Emit(OpCodes.Unbox, declaringType); + mayVirtual = false; + } + else + { + EnsureClass(iLGenerator, declaringType); + } + } + for (var l = 0; l < array.Length; l++) + { + iLGenerator.Emit(parameters[l].ParameterType.IsByRef ? OpCodes.Ldloca_S : OpCodes.Ldloc, array2[l]); + } + if (mb.IsConstructor) + { + iLGenerator.Emit(OpCodes.Newobj, (ConstructorInfo)mb); + EnsureBoxed(iLGenerator, mb.DeclaringType); + } + else + { + var methodInfo = (MethodInfo)mb; + if (!mayVirtual || mb.IsStatic) + { + iLGenerator.EmitCall(OpCodes.Call, methodInfo, null); + } + else + { + iLGenerator.EmitCall(OpCodes.Callvirt, methodInfo, null); + } + if (methodInfo.ReturnType == VoidType) + { + iLGenerator.Emit(OpCodes.Ldnull); + } + else + { + EnsureBoxed(iLGenerator, methodInfo.ReturnType); + } + } + if (flag) + { + var local = iLGenerator.DeclareLocal(SimpleTypeHelper.ObjectType); + iLGenerator.Emit(OpCodes.Stloc, local); + iLGenerator.BeginFinallyBlock(); + for (var m = 0; m < array.Length; m++) + { + if (parameters[m].ParameterType.IsByRef) + { + iLGenerator.Emit(OpCodes.Ldarg_1); + EmitLdc(iLGenerator, m); + iLGenerator.Emit(OpCodes.Ldloc, array2[m]); + if (array2[m].LocalType.IsValueType || ElementedTypeHelper.TryGoToElementType(array2[m].LocalType).IsGenericParameter) + { + iLGenerator.Emit(OpCodes.Box, array2[m].LocalType); + } + iLGenerator.Emit(OpCodes.Stelem_Ref); + } + } + iLGenerator.EndExceptionBlock(); + iLGenerator.Emit(OpCodes.Ldloc, local); + } + iLGenerator.Emit(OpCodes.Ret); + return (DynamicExecutor)dynamicMethod.CreateDelegate(typeof(DynamicExecutor)); + } + + // Token: 0x06000209 RID: 521 RVA: 0x0000C4D0 File Offset: 0x0000A6D0 + private static bool HasByRefParameter(MethodBase mb) // \u0002 + { + return mb.GetParameters().Any(t => t.ParameterType.IsByRef); + } + + // Token: 0x060001D9 RID: 473 RVA: 0x0000A72C File Offset: 0x0000892C + private object Invoke(MethodBase mb, object obj, object[] args) // \u0002 + { + if (mb.IsConstructor) + { + // ReSharper disable once AssignNullToNotNullAttribute + return Activator.CreateInstance(mb.DeclaringType, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, args, null); + } + return mb.Invoke(obj, args); + } + + // Token: 0x06000286 RID: 646 RVA: 0x00011EFC File Offset: 0x000100FC + private object InvokeDynamic(MethodBase mb, object obj, object[] args, bool mayVirtual) // \u0002 + { + /*if (!_alwaysTrue) + { + return Invoke(mb, obj, args); + }*/ + var key = new MethodBaseAndVirtual(mb, mayVirtual); + DynamicExecutor executor; + lock (_dynamicExecutors) + { + _dynamicExecutors.TryGetValue(key, out executor); + } + if (executor == null) + { + bool needFaster; + lock (_mbCallCnt) + { + int num; + _mbCallCnt.TryGetValue(mb, out num); + needFaster = num >= 50; + if (!needFaster) + { + _mbCallCnt[mb] = num + 1; + } + } + if (!needFaster && !mayVirtual && obj == null && !mb.IsStatic && !mb.IsConstructor) + { + needFaster = true; + } + if (!needFaster && HasByRefParameter(mb)) + { + needFaster = true; + } + if (!needFaster) + { + return Invoke(mb, obj, args); + } + lock (_mbDynamicLock) + { + while (_mbDynamicLock.ContainsKey(mb)) + { + Monitor.Wait(_mbDynamicLock); + } + _mbDynamicLock[mb] = null; + } + try + { + lock (_dynamicExecutors) + { + _dynamicExecutors.TryGetValue(key, out executor); + } + if (executor == null) + { + executor = DynamicFor(mb, mayVirtual); + lock (_dynamicExecutors) + { + _dynamicExecutors[key] = executor; + } + } + lock (_mbCallCnt) + { + _mbCallCnt.Remove(mb); + } + } + finally + { + lock (_mbDynamicLock) + { + _mbDynamicLock.Remove(mb); + Monitor.PulseAll(_mbDynamicLock); + } + } + } + return executor(obj, args); + } + + // Token: 0x0600028D RID: 653 RVA: 0x000122A4 File Offset: 0x000104A4 + private VariantBase FetchByAddr(VariantBase addr) // \u0003 + { + if (!addr.IsAddr()) + { + throw new ArgumentException(); + } + var num = addr.GetTypeCode(); + if (num == VariantBase.Vtc.Tc0VariantBaseHolder) + { + return ((VariantBaseHolder)addr).GetValue(); + } + if (num != VariantBase.Vtc.Tc4FieldInfo) + { + switch (num) + { + case VariantBase.Vtc.Tc20MdArrayValue: + case VariantBase.Vtc.Tc22SdArrayValue: + { + var avv = (ArrayValueVariantBase)addr; + return VariantFactory.Convert(avv.GetValue(), avv.GetHeldType()); + } + case VariantBase.Vtc.Tc23LocalsIdxHolder: + return _localVariables[((LocalsIdxHolderVariant)addr).GetValue()]; + } + throw new ArgumentOutOfRangeException(); + } + var fiv = (FieldInfoVariant)addr; + return VariantFactory.Convert(fiv.GetValue().GetValue(fiv.GetObject()), null); + } + + // Token: 0x06000186 RID: 390 RVA: 0x00008150 File Offset: 0x00006350 + private FieldInfo ResolveField(int id) // \u0002 + { + FieldInfo result; + lock (AllMetadataById) + { + object md; + if (AllMetadataById.TryGetValue(id, out md)) + { + result = (FieldInfo)md; + } + else + { + var U0003U2008 = ReadToken(id); + if (U0003U2008.IsVm == 0) + { + result = _module.ResolveField(U0003U2008.MetadataToken); + } + else + { + var u000Fu2006 = (VmFieldTokenInfo)U0003U2008.VmToken; + var expr_70 = GetTypeById(u000Fu2006.Class.MetadataToken); + var bindingAttr = BF(u000Fu2006.IsStatic); + var field = expr_70.GetField(u000Fu2006.Name, bindingAttr); + if (!expr_70.IsGenericType) + { + AllMetadataById.Add(id, field); + } + result = field; + } + } + } + return result; + } + + // Token: 0x06000177 RID: 375 RVA: 0x00007CD8 File Offset: 0x00005ED8 + private void Ldflda_(VariantBase vFieldId) // \u0003\u2009 + { + var fieldInfo = ResolveField(((IntVariant)vFieldId).GetValue()); + var reference = PopVariant(); + var obj = reference.IsAddr() ? FetchByAddr(reference).GetValueAbstract() : reference.GetValueAbstract(); + var val = new FieldInfoVariant(); + val.SetValue(fieldInfo); + val.SetObject(obj); + PushVariant(val); + } + + // Token: 0x0600018F RID: 399 RVA: 0x0000840C File Offset: 0x0000660C + private void Ldsflda_(VariantBase vFieldId) // \u000E\u2002 + { + var fieldInfo = ResolveField(((IntVariant)vFieldId).GetValue()); + var val = new FieldInfoVariant(); + val.SetValue(fieldInfo); + PushVariant(val); + } + + // Token: 0x0600017D RID: 381 RVA: 0x00007E20 File Offset: 0x00006020 + private void Ldtoken_(VariantBase vToken) // \u0005\u2002\u2000 + { + var t = ReadToken(((IntVariant)vToken).GetValue()); + object obj; + if (t.IsVm == 0) + { + obj = ResolveNativeToken(t.MetadataToken); + } + else + { + switch (t.VmToken.TokenKind()) + { + case VmTokenInfo.Kind.Class0: + obj = GetTypeById(((IntVariant)vToken).GetValue()).TypeHandle; + break; + case VmTokenInfo.Kind.Field1: + obj = ResolveField(((IntVariant)vToken).GetValue()).FieldHandle; + break; + case VmTokenInfo.Kind.Method2: + obj = FindMethodById(((IntVariant)vToken).GetValue()).MethodHandle; + break; + default: + throw new InvalidOperationException(); + } + } + var push = new ObjectVariant(); + push.SetValue(obj); + PushVariant(push); + } + + // Token: 0x06000206 RID: 518 RVA: 0x0000C1C8 File Offset: 0x0000A3C8 + private void Ldfld_(VariantBase vFieldId) // \u0005\u2003\u2001 + { + var fieldInfo = ResolveField(((IntVariant)vFieldId).GetValue()); + var reference = PopVariant(); + if (reference.IsAddr()) + { + reference = FetchByAddr(reference); + } + var obj = reference.GetValueAbstract(); + if (obj == null) + { + throw new NullReferenceException(); + } + PushVariant(VariantFactory.Convert(fieldInfo.GetValue(obj), fieldInfo.FieldType)); + } + + // Token: 0x06000225 RID: 549 RVA: 0x0000F2CC File Offset: 0x0000D4CC + private void Ldsfld_(VariantBase vFieldId) // \u000F\u2004\u2000 + { + var fieldInfo = ResolveField(((IntVariant)vFieldId).GetValue()); + PushVariant(VariantFactory.Convert(fieldInfo.GetValue(null), fieldInfo.FieldType)); + } + + // Token: 0x0600024A RID: 586 RVA: 0x0001034C File Offset: 0x0000E54C + private void Newobj_(VariantBase vCtrId) // \u0002\u200A + { + var num = ((IntVariant)vCtrId).GetValue(); + var methodBase = FindMethodById(num); + var declaringType = methodBase.DeclaringType; + var parameters = methodBase.GetParameters(); + var expr_2A = parameters.Length; + var array = new object[expr_2A]; + var dictionary = new Dictionary<int, VariantBase>(); + for (var i = expr_2A - 1; i >= 0; i--) + { + var u000F = PopVariant(); + if (u000F.IsAddr()) + { + dictionary.Add(i, u000F); + u000F = FetchByAddr(u000F); + } + if (u000F.GetVariantType() != null) + { + u000F = VariantFactory.Convert(null, u000F.GetVariantType()).CopyFrom(u000F); + } + var u000F2 = VariantFactory.Convert(null, parameters[i].ParameterType).CopyFrom(u000F); + array[i] = u000F2.GetValueAbstract(); + } + object obj; + try + { + obj = InvokeDynamic(methodBase, null, array, false); + } + catch (TargetInvocationException ex) + { + var expr_C2 = ex.InnerException ?? ex; + SerializeCrossDomain(expr_C2); + throw expr_C2; + } + foreach (var current in dictionary) + { + AssignByReference(current.Value, VariantFactory.Convert(array[current.Key], null)); + } + PushVariant(VariantFactory.Convert(obj, declaringType)); + } + + // Token: 0x06000227 RID: 551 RVA: 0x0000F3B4 File Offset: 0x0000D5B4 + private void AssignByReference(VariantBase refDest, VariantBase val) // \u0002 + { + switch (refDest.GetTypeCode()) + { + case VariantBase.Vtc.Tc0VariantBaseHolder: + ((VariantBaseHolder)refDest).GetValue().CopyFrom(val); + return; + case VariantBase.Vtc.Tc4FieldInfo: + var refFieldInfoDest = (FieldInfoVariant)refDest; + var fieldInfo = refFieldInfoDest.GetValue(); + fieldInfo.SetValue(refFieldInfoDest.GetObject(), VariantFactory.Convert(val.GetValueAbstract(), fieldInfo.FieldType).GetValueAbstract()); + return; + case VariantBase.Vtc.Tc20MdArrayValue: + case VariantBase.Vtc.Tc22SdArrayValue: + var refArrayValueDest = (ArrayValueVariantBase)refDest; + refArrayValueDest.SetValue(VariantFactory.Convert(val.GetValueAbstract(), refArrayValueDest.GetHeldType()).GetValueAbstract()); + return; + case VariantBase.Vtc.Tc23LocalsIdxHolder: + _localVariables[((LocalsIdxHolderVariant)refDest).GetValue()].CopyFrom(val); + return; + default: + throw new ArgumentOutOfRangeException(); + } + } + + // Token: 0x060001E5 RID: 485 RVA: 0x0000AD10 File Offset: 0x00008F10 + private void Invoke(MethodBase mb, bool mayVirtual) // \u0002 + { + if (!mayVirtual && IsCompatible(mb)) + { + mb = GenerateDynamicCall(mb, false); + } + var parameters = mb.GetParameters(); + var num = parameters.Length; + var poppedArgs = new VariantBase[num]; + var args = new object[num]; + var wasLocked = default(BoolHolder); + try + { + LockIfInterlocked(ref wasLocked, mb, mayVirtual); + for (var i = num - 1; i >= 0; i--) + { + var u000F = PopVariant(); + poppedArgs[i] = u000F; + if (u000F.IsAddr()) + { + u000F = FetchByAddr(u000F); + } + if (u000F.GetVariantType() != null) + { + u000F = VariantFactory.Convert(null, u000F.GetVariantType()).CopyFrom(u000F); + } + var u000F2 = VariantFactory.Convert(null, parameters[i].ParameterType).CopyFrom(u000F); + args[i] = u000F2.GetValueAbstract(); + } + VariantBase u000F3 = null; + if (!mb.IsStatic) + { + u000F3 = PopVariant(); + if (u000F3?.GetVariantType() != null) + { + u000F3 = VariantFactory.Convert(null, u000F3.GetVariantType()).CopyFrom(u000F3); + } + } + object obj = null; + try + { + if (mb.IsConstructor) + { + obj = Activator.CreateInstance(mb.DeclaringType, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, args, null); + if (u000F3 != null && !u000F3.IsAddr()) + { + throw new InvalidOperationException(); + } + AssignByReference(u000F3, VariantFactory.Convert(obj, mb.DeclaringType)); + } + else + { + object poppedThis = null; + if (u000F3 != null) + { + var u000F4 = u000F3; + if (u000F3.IsAddr()) + { + u000F4 = FetchByAddr(u000F3); + } + poppedThis = u000F4.GetValueAbstract(); + } + try + { + if (!InvokeFilter(mb, poppedThis, ref obj, args)) + { + if (mayVirtual && !mb.IsStatic && poppedThis == null) + { + throw new NullReferenceException(); + } + if (!AlwaysFalse(mb, poppedThis, poppedArgs, args, mayVirtual, ref obj)) + { + obj = InvokeDynamic(mb, poppedThis, args, mayVirtual); + } + } + if (u000F3 != null && u000F3.IsAddr()) + { + AssignByReference(u000F3, VariantFactory.Convert(poppedThis, mb.DeclaringType)); + } + } + catch (TargetInvocationException ex) + { + var cause = ex.InnerException ?? ex; + SerializeCrossDomain(cause); + throw cause; + } + } + } + finally + { + for (var j = 0; j < poppedArgs.Length; j++) + { + var u000F5 = poppedArgs[j]; + if (u000F5.IsAddr()) + { + var obj3 = args[j]; + AssignByReference(u000F5, VariantFactory.Convert(obj3, null)); + } + } + } + var methodInfo = mb as MethodInfo; + if (methodInfo != null) + { + var returnType = methodInfo.ReturnType; + if (returnType != VoidType) + { + PushVariant(VariantFactory.Convert(obj, returnType)); + } + } + } + finally + { + UnlockInterlockedIfAny(ref wasLocked); + } + } + + // Token: 0x060001FD RID: 509 RVA: 0x0000BD88 File Offset: 0x00009F88 + private void DoJmp(int pos, Type[] methodGenericArgs, Type[] classGenericArgs, bool mayVirtual) // \u0002 + { + _srcVirtualizedStreamReader.BaseStream.Seek(pos, SeekOrigin.Begin); + DoNothing(_srcVirtualizedStreamReader); + var u0006 = ReadMethodHeader(_srcVirtualizedStreamReader); + var num = u0006.ArgsTypeToOutput.Length; + var array = new object[num]; + var array2 = new VariantBase[num]; + if (_currentClass != null & mayVirtual) + { + var num2 = u0006.IsStatic() ? 0 : 1; + var array3 = new Type[num - num2]; + for (var i = num - 1; i >= num2; i--) + { + array3[i] = GetTypeById(u0006.ArgsTypeToOutput[i].TypeId); + } + var method = _currentClass.GetMethod(u0006.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.GetProperty | BindingFlags.SetProperty, null, array3, null); + _currentClass = null; + if (method != null) + { + Invoke(method, true); + return; + } + } + for (var j = num - 1; j >= 0; j--) + { + var u000F = PopVariant(); + array2[j] = u000F; + if (u000F.IsAddr()) + { + u000F = FetchByAddr(u000F); + } + if (u000F.GetVariantType() != null) + { + u000F = VariantFactory.Convert(null, u000F.GetVariantType()).CopyFrom(u000F); + } + var u000F2 = VariantFactory.Convert(null, GetTypeById(u0006.ArgsTypeToOutput[j].TypeId)).CopyFrom(u000F); + array[j] = u000F2.GetValueAbstract(); + if (j == 0 & mayVirtual && !u0006.IsStatic() && array[j] == null) + { + throw new NullReferenceException(); + } + } + var u0006u2007 = new VmExecutor(_instrCodesDb); + var callees = new object[] + { + _module.Assembly + }; + object obj; + try + { + obj = u0006u2007.Invoke(_srcVirtualizedStream, pos, array, methodGenericArgs, classGenericArgs, callees); + } + finally + { + for (var k = 0; k < array2.Length; k++) + { + var u000F3 = array2[k]; + if (u000F3.IsAddr()) + { + var obj2 = array[k]; + AssignByReference(u000F3, VariantFactory.Convert(obj2, null)); + } + } + } + var type = u0006u2007.GetTypeById(u0006u2007._methodHeader.ReturnTypeId); + if (type != VoidType) + { + PushVariant(VariantFactory.Convert(obj, type)); + } + } + + // Token: 0x0600027A RID: 634 RVA: 0x00011994 File Offset: 0x0000FB94 + private void JmpToRef(VmMethodRefTokenInfo mref) // \u0002 + { + //var arg_18_0 = (U0008U2007)U0003U2008.Get_u0005(); + var methodBase = FindMethodById(mref.Pos, ReadToken(mref.Pos)); + //methodBase.GetParameters(); + var num = mref.Flags; + var mayVirtual = (num & 1073741824) != 0; + num &= -1073741825; + var methodGenericArgs = _methodGenericArgs; + var classGenericArgs = _classGenericArgs; + try + { + _methodGenericArgs = methodBase is ConstructorInfo ? Type.EmptyTypes : methodBase.GetGenericArguments(); + _classGenericArgs = methodBase.DeclaringType.GetGenericArguments(); + DoJmp(num, _methodGenericArgs, _classGenericArgs, mayVirtual); + } + finally + { + _methodGenericArgs = methodGenericArgs; + _classGenericArgs = classGenericArgs; + } + } + + // Token: 0x060001EE RID: 494 RVA: 0x0000B5FC File Offset: 0x000097FC + private void Jmp_(VariantBase vPos) // \u0008\u200B\u2000 + { + var pos = ((IntVariant)vPos).GetValue(); + var arg_29_0 = (pos & -2147483648) != 0; + var mayVirtual = (pos & 1073741824) != 0; + pos &= 1073741823; + if (arg_29_0) + { + DoJmp(pos, null, null, mayVirtual); + return; + } + JmpToRef((VmMethodRefTokenInfo)ReadToken(pos).VmToken); + } + + // Token: 0x06000199 RID: 409 RVA: 0x00008660 File Offset: 0x00006860 + private void Calli_(VariantBase dummy) // \u0003\u2002 + { + var methodBase = ((MethodVariant)PopVariant()).GetValue(); + Invoke(methodBase, false); + } + + // Token: 0x06000184 RID: 388 RVA: 0x000080F4 File Offset: 0x000062F4 + private void Call_(VariantBase vMethodId) // \u000E\u2003 + { + var methodBase = FindMethodById(((IntVariant)vMethodId).GetValue()); + foreach (var arg in _variantOutputArgs) + { + PushVariant(arg); + } + Invoke(methodBase, false); + } + + // Token: 0x06000191 RID: 401 RVA: 0x0000845C File Offset: 0x0000665C + private void Callvirt_(VariantBase vMethodId) // \u000E\u2005 + { + var methodBase = FindMethodById(((IntVariant)vMethodId).GetValue()); + if (_currentClass != null) + { + var pars = methodBase.GetParameters(); + var types = new Type[pars.Length]; + var num = 0; + foreach (var parameterInfo in pars) + { + types[num++] = parameterInfo.ParameterType; + } + var method = _currentClass.GetMethod(methodBase.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.GetProperty | BindingFlags.SetProperty, null, types, null); + if (method != null) + { + methodBase = method; + } + _currentClass = null; + } + Invoke(methodBase, true); + } + + // Token: 0x060001CE RID: 462 RVA: 0x0000A1A0 File Offset: 0x000083A0 + private void Invoke(VariantBase vMethodId) // \u000E\u200A + { + var methodBase = FindMethodById(((IntVariant)vMethodId).GetValue()); + Invoke(methodBase, false); + } + + // Token: 0x06000205 RID: 517 RVA: 0x0000C1A8 File Offset: 0x0000A3A8 + [DebuggerNonUserCode] + private MethodBase FindMethodById(int methodId) // \u0002 + { + return FindMethodById(methodId, ReadToken(methodId)); + } + + // Token: 0x06000171 RID: 369 RVA: 0x00007BBC File Offset: 0x00005DBC + private object Invoke(Stream srcVirtualizedStream, int pos, object[] args, Type[] methodGenericArgs, Type[] classGenericArgs, object[] callees) // \u0002 + { + _srcVirtualizedStream = srcVirtualizedStream; + Seek(pos, srcVirtualizedStream, null); + return Invoke(args, methodGenericArgs, classGenericArgs, callees); + } + + // Token: 0x06000172 RID: 370 RVA: 0x00007BDC File Offset: 0x00005DDC + private bool AlwaysFalse(MethodBase mb, object poppedThis, VariantBase[] poppedArgs, object[] args, bool mayVirtual, ref object obj) // \u0002 + { + return false; + } + + // Token: 0x06000179 RID: 377 RVA: 0x00007DA8 File Offset: 0x00005FA8 + private void Leave_(VariantBase vTarget) // \u0006\u200B + { + OnException(null, ((UintVariant)vTarget).GetValue()); + } + + // Token: 0x06000180 RID: 384 RVA: 0x00007F48 File Offset: 0x00006148 + private void Castclass_(VariantBase vTypeId) // \u0005\u2003 + { + var type = GetTypeById(((IntVariant)vTypeId).GetValue()); + var obj = PopVariant(); + if (Isinst(obj, type)) + { + PushVariant(obj); + return; + } + throw new InvalidCastException(); + } + + // Token: 0x06000185 RID: 389 RVA: 0x00008144 File Offset: 0x00006344 + private void Ldc_i4_s_(VariantBase val) // \u000E\u2003\u2000 + { + PushVariant(val); + } + + // Token: 0x0600018B RID: 395 RVA: 0x0000827C File Offset: 0x0000647C + private void Stelem_i2_(VariantBase dummy) // \u000E\u200A\u2000 + { + var obj = PopVariant().GetValueAbstract(); + var idx = PopLong(); + var array = (Array)PopVariant().GetValueAbstract(); + var elementType = array.GetType().GetElementType(); + checked + { + if (elementType == typeof(short)) + { + ((short[])array)[(int)(IntPtr)idx] = (short)VariantFactory.Convert(obj, typeof(short)).GetValueAbstract(); + return; + } + if (elementType == typeof(ushort)) + { + ((ushort[])array)[(int)(IntPtr)idx] = (ushort)VariantFactory.Convert(obj, typeof(ushort)).GetValueAbstract(); + return; + } + if (elementType == typeof(char)) + { + ((char[])array)[(int)(IntPtr)idx] = (char)VariantFactory.Convert(obj, typeof(char)).GetValueAbstract(); + return; + } + if (elementType.IsEnum) + { + Stelem(elementType, obj, idx, array); + return; + } + Stelem(typeof(short), obj, idx, array); + } + } + + // Token: 0x0600018E RID: 398 RVA: 0x00008404 File Offset: 0x00006604 + private void Stind_i_(VariantBase dummy) // \u000F\u2006 + { + Stind(); + } + + // Token: 0x06000190 RID: 400 RVA: 0x00008440 File Offset: 0x00006640 + private void Ldloc_0_(VariantBase dummy) // \u0006 + { + PushVariant(_localVariables[0].Clone()); + } + + // Token: 0x06000193 RID: 403 RVA: 0x00008508 File Offset: 0x00006708 + private void And_(VariantBase dummy) // \u000F\u200B\u2000 + { + PushVariant(And(PopVariant(), PopVariant())); + } + + // Token: 0x06000194 RID: 404 RVA: 0x00008534 File Offset: 0x00006734 + private void Bge_un_(VariantBase vpos) // \u0006\u2009 + { + var v2 = PopVariant(); + if (UniCompare(PopVariant(), v2, ComparisonKind.GE, true)) + { + JumpToPos(((UintVariant)vpos).GetValue()); + } + } + + // Token: 0x06000198 RID: 408 RVA: 0x00008628 File Offset: 0x00006828 + private void Blt_un_(VariantBase vpos) // \u0006\u2006\u2000 + { + var v2 = PopVariant(); + if (UniCompare(PopVariant(), v2, ComparisonKind.LT, true)) + { + JumpToPos(((UintVariant)vpos).GetValue()); + } + } + + // Token: 0x06000234 RID: 564 RVA: 0x0000F934 File Offset: 0x0000DB34 + private void Bge_(VariantBase vpos) // \u0002\u200B + { + var v2 = PopVariant(); + if (UniCompare(PopVariant(), v2, ComparisonKind.GE, false)) + { + JumpToPos(((UintVariant)vpos).GetValue()); + } + } + + // Token: 0x060002AB RID: 683 RVA: 0x00012D80 File Offset: 0x00010F80 + private void Blt_(VariantBase vpos) // \u0003\u2001 + { + var v2 = PopVariant(); + if (UniCompare(PopVariant(), v2, ComparisonKind.LT, false)) + { + JumpToPos(((UintVariant)vpos).GetValue()); + } + } + + // Token: 0x0600023D RID: 573 RVA: 0x0000FA1C File Offset: 0x0000DC1C + private void Bgt_(VariantBase vpos) // \u000F\u2000\u2001 + { + var v2 = PopVariant(); + if (UniCompare(PopVariant(), v2, ComparisonKind.GT, false)) + { + JumpToPos(((UintVariant)vpos).GetValue()); + } + } + + // Token: 0x060001A3 RID: 419 RVA: 0x00008D10 File Offset: 0x00006F10 + private void Bgt_un_(VariantBase vpos) // \u0005\u2004 + { + var v2 = PopVariant(); + if (UniCompare(PopVariant(), v2, ComparisonKind.GT, true)) + { + JumpToPos(((UintVariant)vpos).GetValue()); + } + } + + // Token: 0x06000261 RID: 609 RVA: 0x00010BB4 File Offset: 0x0000EDB4 + private void Bne_un_(VariantBase vpos) // \u000F\u2007 + { + var v2 = PopVariant(); + if (UniCompare(PopVariant(), v2, ComparisonKind.NEQ, true)) + { + JumpToPos(((UintVariant)vpos).GetValue()); + } + } + + // Token: 0x0600029D RID: 669 RVA: 0x000126E0 File Offset: 0x000108E0 + private void Beq_(VariantBase vpos) // \u0002\u2007\u2000 + { + var v2 = PopVariant(); + if (UniCompare(PopVariant(), v2, ComparisonKind.EQ, false)) + { + JumpToPos(((UintVariant)vpos).GetValue()); + } + } + + // Token: 0x060001B9 RID: 441 RVA: 0x000093F8 File Offset: 0x000075F8 + private void Ble_un_(VariantBase vpos) // \u0003\u2007\u2000 + { + var v2 = PopVariant(); + var v1 = PopVariant(); + if (UniCompare(v1, v2, ComparisonKind.LE, true)) + { + JumpToPos(((UintVariant)vpos).GetValue()); + } + } + + private static bool IsFloating(VariantBase v) + { + return v.GetTypeCode() == VariantBase.Vtc.Tc21Double || v.GetTypeCode() == VariantBase.Vtc.Tc8Float; + } + // Token: 0x06000297 RID: 663 RVA: 0x0001253C File Offset: 0x0001073C + private void Ble_(VariantBase vpos) // \u0002\u2003\u2000 + { + var v2 = PopVariant(); + var v1 = PopVariant(); + if (UniCompare(v1, v2, ComparisonKind.LE, false)) + { + JumpToPos(((UintVariant)vpos).GetValue()); + } + } + + // Token: 0x06000228 RID: 552 RVA: 0x0000F480 File Offset: 0x0000D680 + private void Brfalse_(VariantBase vpos) // \u0002\u2002 + { + var val = PopVariant(); + var num = val.GetTypeCode(); + bool flag; + switch (num) + { + case VariantBase.Vtc.Tc5Enum: + flag = !Convert.ToBoolean(((EnumVariant)val).GetValue()); + break; + case VariantBase.Vtc.Tc13UIntPtr: + flag = ((UIntPtrVariant)val).GetValue() == UIntPtr.Zero; + break; + case VariantBase.Vtc.Tc17IntPtr: + flag = ((IntPtrVariant)val).GetValue() == IntPtr.Zero; + break; + case VariantBase.Vtc.Tc18Object: + flag = ((ObjectVariant)val).GetValue() == null; + break; + case VariantBase.Vtc.Tc19Int: + flag = ((IntVariant)val).GetValue() == 0; + break; + case VariantBase.Vtc.Tc24Long: + flag = ((LongVariant)val).GetValue() == 0L; + break; + default: + flag = val.GetValueAbstract() == null; + break; + } + if (flag) + { + JumpToPos(((UintVariant)vpos).GetValue()); + } + } + + // Token: 0x06000274 RID: 628 RVA: 0x00011488 File Offset: 0x0000F688 + private void ExecuteExceptionHandler() // \u0005 + { + if (_ehStack.Count == 0) + { + if (_wasException) + { + _myBufferPos = _myBufferReader.GetBuffer().GetPos(); + ThrowStoreCrossDomain(_exception); + } + return; + } + var ehFrame = _ehStack.PopBack(); + if (ehFrame.Exception != null) + { + var toStack = new ObjectVariant(); + toStack.SetValueAbstract(ehFrame.Exception); + PushVariant(toStack); + } + else + { + _evalStack.Clear(); + } + JumpToPos(ehFrame.Pos); + } + + // Token: 0x060001F2 RID: 498 RVA: 0x0000B6C8 File Offset: 0x000098C8 + private void Switch_(VariantBase vSwitchPosArray) // \u0002\u200A\u2000 + { + var vidx = PopVariant(); + uint idx; + switch (vidx.GetTypeCode()) + { + case VariantBase.Vtc.Tc5Enum: + idx = (uint)Convert.ToInt64(vidx.GetValueAbstract()); + break; + case VariantBase.Vtc.Tc19Int: + idx = (uint)((IntVariant)vidx).GetValue(); + break; + case VariantBase.Vtc.Tc24Long: + idx = (uint)((LongVariant)vidx).GetValue(); + break; + default: + throw new InvalidOperationException(); + } + var switchPosArray = (IntVariant[])((ArrayVariant)vSwitchPosArray).GetValue(); + if (idx >= (ulong)switchPosArray.Length) + { + return; + } + JumpToPos((uint)switchPosArray[(int)idx].GetValue()); + } + + // Token: 0x060001FB RID: 507 RVA: 0x0000BC68 File Offset: 0x00009E68 + private void Brtrue_(VariantBase vpos) // \u0008\u2007 + { + var val = PopVariant(); + var num = val.GetTypeCode(); + bool flag; + switch (num) + { + case VariantBase.Vtc.Tc5Enum: + flag = Convert.ToBoolean(((EnumVariant)val).GetValue()); + break; + case VariantBase.Vtc.Tc13UIntPtr: + flag = ((UIntPtrVariant)val).GetValue() != UIntPtr.Zero; + break; + case VariantBase.Vtc.Tc17IntPtr: + flag = ((IntPtrVariant)val).GetValue() != IntPtr.Zero; + break; + case VariantBase.Vtc.Tc18Object: + flag = ((ObjectVariant)val).GetValue() != null; + break; + case VariantBase.Vtc.Tc19Int: + flag = ((IntVariant)val).GetValue() != 0; + break; + case VariantBase.Vtc.Tc24Long: + flag = ((LongVariant)val).GetValue() != 0L; + break; + default: + flag = val.GetValueAbstract() != null; + break; + } + if (flag) + { + JumpToPos(((UintVariant)vpos).GetValue()); + } + } + + // Token: 0x06000214 RID: 532 RVA: 0x0000C764 File Offset: 0x0000A964 + private void Br_(VariantBase vpos) // \u0005\u2008\u2000 + { + JumpToPos(((UintVariant)vpos).GetValue()); + } + + private void Conv_r_un_(VariantBase dummy) + { + var pop = PopVariant(); + double val; + switch (pop.GetTypeCode()) + { + case VariantBase.Vtc.Tc5Enum: + var v = VariantBase.SignedVariantFromEnum((EnumVariant)pop).GetValueAbstract(); + if (Marshal.SizeOf(v) < 8) + val = (double)(uint)Convert.ToInt32(v); + else + val = (double)(ulong)Convert.ToInt64(v); + break; + case VariantBase.Vtc.Tc19Int: + val = (double)(uint)((IntVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc21Double: + val = ((DoubleVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc8Float: + val = (double)((FloatVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc24Long: + val = (double)(ulong)((LongVariant)pop).GetValue(); + break; + default: + // это нужно будет заменить на соотв. msil-код + var dyn = new DynamicMethod(String.Empty, typeof(double), new[] { typeof(object) }, typeof(void), true); + var gen = dyn.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(OpCodes.Conv_R_Un); + gen.Emit(OpCodes.Ret); + val = (double)dyn.Invoke(null, new[] { pop.GetValueAbstract() }); + break; + } + var push = new DoubleVariant(); + push.SetValue(val); + PushVariant(push); + } + + private void Conv_r(OpCode oc, Func<object, double> F) + { + var pop = PopVariant(); + double val; + switch (pop.GetTypeCode()) + { + case VariantBase.Vtc.Tc5Enum: + var v = VariantBase.SignedVariantFromEnum((EnumVariant)pop).GetValueAbstract(); + val = F(Marshal.SizeOf(v) < 8 ? Convert.ToInt32(v) : Convert.ToInt64(v)); + break; + case VariantBase.Vtc.Tc19Int: + val = F(((IntVariant)pop).GetValue()); + break; + case VariantBase.Vtc.Tc21Double: + val = F(((DoubleVariant)pop).GetValue()); + break; + case VariantBase.Vtc.Tc8Float: + val = F(((FloatVariant)pop).GetValue()); + break; + case VariantBase.Vtc.Tc24Long: + val = F(((LongVariant)pop).GetValue()); + break; + default: + // это нужно будет заменить на соотв. msil-код + var dyn = new DynamicMethod(String.Empty, typeof(double), new[] { typeof(object) }, typeof(void), true); + var gen = dyn.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(oc); + gen.Emit(OpCodes.Ret); + val = (double)dyn.Invoke(null, new[] { pop.GetValueAbstract() }); + break; + } + var push = new DoubleVariant(); + push.SetValue(val); + PushVariant(push); + } + private void Conv_r4_(VariantBase dummy) + { + Conv_r(OpCodes.Conv_R4, o => (double)(float)Convert.ChangeType(o, typeof(float))); + } + private void Conv_r8_(VariantBase dummy) + { + Conv_r(OpCodes.Conv_R8, o => (double)Convert.ChangeType(o, typeof(double))); + } + + // Token: 0x06000196 RID: 406 RVA: 0x00008600 File Offset: 0x00006800 + private void Ldind_i4_(VariantBase dummy) // \u0002\u2001\u2000 + { + Ldind(typeof(int)); + } + + // Token: 0x06000197 RID: 407 RVA: 0x00008614 File Offset: 0x00006814 + private void Ldind_u1_(VariantBase dummy) // \u000E + { + Ldind(typeof(byte)); + } + + // Token: 0x0600019A RID: 410 RVA: 0x00008688 File Offset: 0x00006888 + private void Isinst_(VariantBase vTypeId) // \u000F\u2007\u2000 + { + var type = GetTypeById(((IntVariant)vTypeId).GetValue()); + var obj = PopVariant(); + if (Isinst(obj, type)) + { + PushVariant(obj); + return; + } + PushVariant(new ObjectVariant()); + } + + // Token: 0x0600019D RID: 413 RVA: 0x00008B68 File Offset: 0x00006D68 + private void Initobj_(VariantBase vTypeId) // \u0005\u2005\u2000 + { + var type = GetTypeById(((IntVariant)vTypeId).GetValue()); + var dest = PopVariant(); + if (!type.IsValueType) + { + AssignByReference(dest, new ObjectVariant()); + return; + } + var obj = FetchByAddr(dest).GetValueAbstract(); + if (SimpleTypeHelper.IsNullableGeneric(type)) + { + var val = new ObjectVariant(); + val.SetVariantType(type); + AssignByReference(dest, val); + return; + } + var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); + foreach (var fieldInfo in fields) + { + fieldInfo.SetValue(obj, CreateValueTypeInstance(fieldInfo.FieldType)); + } + } + + // Token: 0x0600019E RID: 414 RVA: 0x00008C08 File Offset: 0x00006E08 + private void Ldarg_s_(VariantBase vidx) // \u000E\u2000 + { + var idx = (ByteVariant)vidx; + PushVariant(_variantOutputArgs[idx.GetValue()].Clone()); + } + + // Token: 0x06000244 RID: 580 RVA: 0x00010160 File Offset: 0x0000E360 + private void Ldarga_s_(VariantBase vidx) // \u0008\u2001\u2001 + { + var idx = (ByteVariant)vidx; + var push = new VariantBaseHolder(); + push.SetValue(_variantOutputArgs[idx.GetValue()]); + PushVariant(push); + } + + // Token: 0x06000255 RID: 597 RVA: 0x00010910 File Offset: 0x0000EB10 + private void Ldarga_(VariantBase vidx) // \u0006\u2001 + { + var idx = (UshortVariant)vidx; + var push = new VariantBaseHolder(); + push.SetValue(_variantOutputArgs[idx.GetValue()]); + PushVariant(push); + } + + // Token: 0x0600019F RID: 415 RVA: 0x00008C38 File Offset: 0x00006E38 + private void Endfilter_(VariantBase dummy) // \u000F\u2001\u2000 + { + if (((IntVariant)PopVariant()).GetValue() != 0) + { + _ehStack.PushBack(new ExcHandlerFrame + { + Pos = (uint)_myBufferReader.GetBuffer().GetPos(), + Exception = _exception + }); + _wasException = false; + } + ExecuteExceptionHandler(); + } + + // Token: 0x060001A2 RID: 418 RVA: 0x00008CFC File Offset: 0x00006EFC + private void Ldind_r4_(VariantBase dummy) // \u0008\u2009\u2000 + { + Ldind(typeof(float)); + } + + // Token: 0x060001A4 RID: 420 RVA: 0x00008D48 File Offset: 0x00006F48 + private void Stsfld_(VariantBase vFieldId) // \u000F\u2008 + { + var fieldInfo = ResolveField(((IntVariant)vFieldId).GetValue()); + var val = VariantFactory.Convert(PopVariant().GetValueAbstract(), fieldInfo.FieldType); + fieldInfo.SetValue(null, val.GetValueAbstract()); + } + + // Token: 0x060001A5 RID: 421 RVA: 0x00008D90 File Offset: 0x00006F90 + private void Ldloc_3_(VariantBase dummy) // \u0003\u2001\u2001 + { + PushVariant(_localVariables[3].Clone()); + } + + // Token: 0x060001A7 RID: 423 RVA: 0x00008F68 File Offset: 0x00007168 + private void Stelem_r8_(VariantBase dummy) // \u000E\u2006\u2000 + { + Stelem(typeof(double)); + } + + // Token: 0x060001AA RID: 426 RVA: 0x00008FBC File Offset: 0x000071BC + private void Ceq_(VariantBase dummy) // \u0006\u2008 + { + var iv = new IntVariant(); + iv.SetValue(UniCompare(PopVariant(), PopVariant(), ComparisonKind.EQ, false) ? 1 : 0); + PushVariant(iv); + } + + // Token: 0x060001AC RID: 428 RVA: 0x00009030 File Offset: 0x00007230 + private void Stelem_i4_(VariantBase dummy) // \u000E\u2001\u2000 + { + var obj = PopVariant().GetValueAbstract(); + var idx = PopLong(); + var array = (Array)PopVariant().GetValueAbstract(); + var elementType = array.GetType().GetElementType(); + checked + { + if (elementType == typeof(int)) + { + ((int[])array)[(int)(IntPtr)idx] = (int)VariantFactory.Convert(obj, typeof(int)).GetValueAbstract(); + return; + } + if (elementType == typeof(uint)) + { + ((uint[])array)[(int)(IntPtr)idx] = (uint)VariantFactory.Convert(obj, typeof(uint)).GetValueAbstract(); + return; + } + if (elementType.IsEnum) + { + Stelem(elementType, obj, idx, array); + return; + } + Stelem(typeof(int), obj, idx, array); + } + } + + // Token: 0x060001AD RID: 429 RVA: 0x00009100 File Offset: 0x00007300 + private void Stind_i1_(VariantBase dummy) // \u0005\u2000\u2000 + { + Stind(); + } + + // Token: 0x060001AF RID: 431 RVA: 0x00009114 File Offset: 0x00007314 + private object ResolveNativeToken(int token) // \u0002 + { + var num = HiByte.Extract(token); + object result; + if (num > 67108864) + { + if (num <= 167772160) + { + if (num != 100663296) + { + if (num != 167772160) + { + throw new InvalidOperationException(); + } + try + { + result = _module.ModuleHandle.ResolveFieldHandle(token); + return result; + } + catch + { + try + { + result = _module.ModuleHandle.ResolveMethodHandle(token); + } + catch + { + throw new InvalidOperationException(); + } + return result; + } + } + } + else + { + if (num == 452984832) + { + result = _module.ModuleHandle.ResolveTypeHandle(token); + return result; + } + if (num != 721420288) + { + throw new InvalidOperationException(); + } + } + result = _module.ModuleHandle.ResolveMethodHandle(token); + return result; + } + if (num != 16777216 && num != 33554432) + { + if (num != 67108864) + { + throw new InvalidOperationException(); + } + result = _module.ModuleHandle.ResolveFieldHandle(token); + return result; + } + result = _module.ModuleHandle.ResolveTypeHandle(token); + return result; + } + + // Token: 0x060001B0 RID: 432 RVA: 0x0000923C File Offset: 0x0000743C + private void Ldloc_2_(VariantBase dummy) // \u0008\u2008 + { + PushVariant(_localVariables[2].Clone()); + } + + // Token: 0x060001B1 RID: 433 RVA: 0x00009258 File Offset: 0x00007458 + private void Constrained_(VariantBase vTypeId) // \u0002\u2000\u2000 + { + _currentClass = GetTypeById(((IntVariant)vTypeId).GetValue()); + } + + // Token: 0x060001B2 RID: 434 RVA: 0x00009280 File Offset: 0x00007480 + private void Ldftn_(VariantBase vMethodId) // \U0003\U2008 + { + var methodBase = FindMethodById(((IntVariant)vMethodId).GetValue()); + var push = new MethodVariant(); + push.SetValue(methodBase); + PushVariant(push); + } + + // Token: 0x060001B4 RID: 436 RVA: 0x000092C8 File Offset: 0x000074C8 + private void Ldnull_(VariantBase dummy) // \u0005\u2002\u2001 + { + PushVariant(new ObjectVariant()); + } + + private void Conv_ovf_u8_un_(VariantBase dummy) + { + Conv_u8(true, false); + } + + // Token: 0x060001B8 RID: 440 RVA: 0x000093F0 File Offset: 0x000075F0 + private void Stind_i2_(VariantBase dummy) // \u0003\u2000\u2000 + { + Stind(); + } + + private void Conv_ovf_u2_un_(VariantBase dummy) + { + Conv_u2(true, false); + } + + private void Conv_u2(bool ovf, bool signed) + { + var pop = PopVariant(); + ushort val; + switch (pop.GetTypeCode()) + { + case VariantBase.Vtc.Tc5Enum: + if (ovf) + { + var v = VariantBase.SignedVariantFromEnum((EnumVariant)pop).GetValueAbstract(); + if (signed) + val = Convert.ToUInt16(v); + else + val = Convert.ToUInt16((ulong)Convert.ToInt64(v)); + break; + } + val = (ushort)VariantBase.SignedLongFromEnum((EnumVariant)pop); + break; + case VariantBase.Vtc.Tc19Int: + if (ovf && !signed) + { + val = Convert.ToUInt16((uint)((IntVariant)pop).GetValue()); + break; + } + val = ovf ? Convert.ToUInt16(((IntVariant)pop).GetValue()) : (ushort)((IntVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc21Double: + if (ovf) + { + val = checked((ushort) ((DoubleVariant) pop).GetValue()); + break; + } + val = (ushort)((DoubleVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc8Float: + if (ovf) + { + val = checked((ushort)((FloatVariant)pop).GetValue()); + break; + } + val = (ushort)((FloatVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc24Long: + if (ovf) + { + if (signed) + val = checked((ushort)((LongVariant)pop).GetValue()); + else + val = Convert.ToUInt16((ulong)((LongVariant)pop).GetValue()); + break; + } + val = (ushort)((LongVariant)pop).GetValue(); + break; + default: + // это нужно будет заменить на соотв. msil-код + var dyn = new DynamicMethod(String.Empty, typeof(ushort), new[] { typeof(object) }, typeof(void), true); + var gen = dyn.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(signed ? (ovf ? OpCodes.Conv_Ovf_U2 : OpCodes.Conv_U2) : OpCodes.Conv_Ovf_U2_Un); + gen.Emit(OpCodes.Ret); + val = (ushort)dyn.Invoke(null, new[] { pop.GetValueAbstract() }); + break; + } + var push = new UshortVariant(); + push.SetValue(val); + PushVariant(push); + } + + // Token: 0x060001AE RID: 430 RVA: 0x00009108 File Offset: 0x00007308 + private void Conv_ovf_u2_(VariantBase dummy) // \u0008\u2005\u2000 + { + Conv_u2(true, true); + } + + // Token: 0x06000292 RID: 658 RVA: 0x0001238C File Offset: 0x0001058C + private void Conv_u2_(VariantBase dummy) // \u000F\u2002\u2000 + { + Conv_u2(false, true); + } + + private void Conv_u1(bool ovf, bool signed) + { + var pop = PopVariant(); + byte val; + switch (pop.GetTypeCode()) + { + case VariantBase.Vtc.Tc5Enum: + if (ovf) + { + var v = VariantBase.SignedVariantFromEnum((EnumVariant)pop).GetValueAbstract(); + val = signed ? Convert.ToByte(v) : Convert.ToByte((ulong)Convert.ToInt64(v)); + break; + } + val = (byte)VariantBase.SignedLongFromEnum((EnumVariant)pop); + break; + case VariantBase.Vtc.Tc19Int: + if (ovf && !signed) + { + val = Convert.ToByte((uint)((IntVariant)pop).GetValue()); + break; + } + val = ovf ? Convert.ToByte(((IntVariant)pop).GetValue()) : (byte)((IntVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc21Double: + if (ovf) + { + val = signed ? checked((byte)((DoubleVariant)pop).GetValue()) : Convert.ToByte(((DoubleVariant)pop).GetValue()); + break; + } + val = (byte)((DoubleVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc8Float: + if (ovf) + { + val = checked((byte)((FloatVariant)pop).GetValue()); + break; + } + val = (byte)((FloatVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc24Long: + if (ovf) + { + val = checked((byte)((LongVariant)pop).GetValue()); + break; + } + val = (byte)((LongVariant)pop).GetValue(); + break; + default: + // это нужно будет заменить на соотв. msil-код + var dyn = new DynamicMethod(String.Empty, typeof(byte), new[] { typeof(object) }, typeof(void), true); + var gen = dyn.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(signed ? (ovf ? OpCodes.Conv_Ovf_U1 : OpCodes.Conv_U1) : OpCodes.Conv_Ovf_U1_Un); + gen.Emit(OpCodes.Ret); + val = (byte)dyn.Invoke(null, new[] { pop.GetValueAbstract() }); + break; + } + var push = new ByteVariant(); + push.SetValue(val); + PushVariant(push); + } + + // Token: 0x06000182 RID: 386 RVA: 0x00007FB4 File Offset: 0x000061B4 + private void Conv_ovf_i1_(VariantBase dummy) // \u0008\u2004 + { + Conv_i1(true, true); + } + + // Token: 0x06000188 RID: 392 RVA: 0x00008238 File Offset: 0x00006438 + private void Conv_u4_(VariantBase dummy) // \u0008\u2003\u2001 + { + Conv_u4(false, true); + } + + // Token: 0x0600018A RID: 394 RVA: 0x00008270 File Offset: 0x00006470 + private void Conv_ovf_i_(VariantBase dummy) // \u0008\u2003\u2000 + { + Conv_i(true, true); + } + + // Token: 0x060001CF RID: 463 RVA: 0x0000A1CC File Offset: 0x000083CC + private void Conv_i_(VariantBase dummy) // \u0008\u2005 + { + Conv_i(false, true); + } + + // Token: 0x060001FF RID: 511 RVA: 0x0000BFC8 File Offset: 0x0000A1C8 + private void Conv_u4(bool ovf, bool signed) // \u0005 + { + var pop = PopVariant(); + uint val; + switch (pop.GetTypeCode()) + { + case VariantBase.Vtc.Tc5Enum: + if (ovf) + { + var v = VariantBase.SignedVariantFromEnum((EnumVariant) pop).GetValueAbstract(); + if (signed || Marshal.SizeOf(v) < 8) + val = signed ? Convert.ToUInt32(v) : (uint)Convert.ToInt32(v); + else + val = Convert.ToUInt32(Convert.ToUInt64(v)); + break; + } + val = (uint)VariantBase.SignedLongFromEnum((EnumVariant)pop); + break; + case VariantBase.Vtc.Tc19Int: + if (ovf && signed) + { + val = checked((uint)((IntVariant)pop).GetValue()); + break; + } + val = (uint)((IntVariant)pop).GetValue(); // err fixed and unit tested by ursoft (was ushort) + break; + case VariantBase.Vtc.Tc21Double: + if (ovf) + { + val = checked((uint)((DoubleVariant)pop).GetValue()); + break; + } + val = (uint)((DoubleVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc8Float: + if (ovf) + { + val = checked((uint)((FloatVariant)pop).GetValue()); + break; + } + val = (uint)((FloatVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc24Long: + if (ovf) + { + val = checked((uint)((LongVariant)pop).GetValue()); + break; + } + val = (uint)((LongVariant)pop).GetValue(); + break; + default: + // это нужно будет заменить на соотв. msil-код + var dyn = new DynamicMethod(String.Empty, typeof(UInt32), new []{ typeof(object) }, typeof(void), true); + var gen = dyn.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(signed ? (ovf ? OpCodes.Conv_Ovf_U4 : OpCodes.Conv_U4) : OpCodes.Conv_Ovf_U4_Un); + gen.Emit(OpCodes.Ret); + val = (uint) dyn.Invoke(null, new[] {pop.GetValueAbstract()}); + break; + } + var push = new IntVariant(); + push.SetValue((int)val); + PushVariant(push); + } + private void Conv_i4(bool ovf, bool signed) + { + var pop = PopVariant(); + int val; + switch (pop.GetTypeCode()) + { + case VariantBase.Vtc.Tc5Enum: + if (ovf) + { + var v = VariantBase.SignedVariantFromEnum((EnumVariant)pop).GetValueAbstract(); + if (signed) + val = Convert.ToInt32(v); + else + val = Convert.ToInt32((ulong)Convert.ToInt64(v)); + break; + } + val = (int)VariantBase.SignedLongFromEnum((EnumVariant)pop); + break; + case VariantBase.Vtc.Tc19Int: + if (ovf && !signed) + { + val = Convert.ToInt32((uint)((IntVariant)pop).GetValue()); + break; + } + val = ((IntVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc21Double: + if (ovf) + { + val = checked((int)((DoubleVariant)pop).GetValue()); + break; + } + val = (int)((DoubleVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc8Float: + if (ovf) + { + val = checked((int)((FloatVariant)pop).GetValue()); + break; + } + val = (int)((FloatVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc24Long: + if (ovf) + { + if(signed) + val = checked((int)((LongVariant)pop).GetValue()); + else + val = Convert.ToInt32((ulong)((LongVariant)pop).GetValue()); + break; + } + val = (int)((LongVariant)pop).GetValue(); + break; + default: + // это нужно будет заменить на соотв. msil-код + var dyn = new DynamicMethod(String.Empty, typeof(Int32), new[] { typeof(object) }, typeof(void), true); + var gen = dyn.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(signed ? (ovf ? OpCodes.Conv_Ovf_I4 : OpCodes.Conv_I4) : OpCodes.Conv_Ovf_I4_Un); + gen.Emit(OpCodes.Ret); + val = (int)dyn.Invoke(null, new[] { pop.GetValueAbstract() }); + break; + } + var push = new IntVariant(); + push.SetValue(val); + PushVariant(push); + } + + // Token: 0x06000294 RID: 660 RVA: 0x00012414 File Offset: 0x00010614 + private void Conv_ovf_u4_(VariantBase dummy) // \u000F\u200A + { + Conv_u4(true, true); + } + + // Token: 0x06000200 RID: 512 RVA: 0x0000C0B0 File Offset: 0x0000A2B0 + private void Conv_ovf_u1_(VariantBase dummy) // \u0008\u2007\u2000 + { + Conv_u1(true, true); + } + + private void Conv_ovf_i2_un_(VariantBase dummy) + { + Conv_i2(true, false); + } + + private void Conv_i2(bool ovf, bool signed) + { + var pop = PopVariant(); + short val; + switch (pop.GetTypeCode()) + { + case VariantBase.Vtc.Tc5Enum: + if (ovf) + { + var v = VariantBase.SignedVariantFromEnum((EnumVariant)pop).GetValueAbstract(); + if (signed) + val = Convert.ToInt16(v); + else + val = Convert.ToInt16((ulong)Convert.ToInt64(v)); + break; + } + val = (short)VariantBase.SignedLongFromEnum((EnumVariant)pop); + break; + case VariantBase.Vtc.Tc19Int: + if (ovf && !signed) + { + val = Convert.ToInt16((uint)((IntVariant)pop).GetValue()); + break; + } + val = ovf ? Convert.ToInt16(((IntVariant)pop).GetValue()) : (short)((IntVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc21Double: + if (ovf) + { + val = signed ? checked((short)((DoubleVariant)pop).GetValue()) : + (IntPtr.Size == 4 ? Convert.ToInt16(Convert.ToUInt16((long)((DoubleVariant)pop).GetValue())) : + Convert.ToInt16((long)((DoubleVariant)pop).GetValue())); + break; + } + val = (short)((DoubleVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc8Float: + if (ovf) + { + val = signed ? checked((short)((FloatVariant)pop).GetValue()) : + (IntPtr.Size == 4 ? Convert.ToInt16(Convert.ToUInt16((long)((FloatVariant)pop).GetValue())) : + Convert.ToInt16((long)((FloatVariant)pop).GetValue())); + break; + } + val = (short)((FloatVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc24Long: + if (ovf) + { + if (signed) + val = checked((short)((LongVariant)pop).GetValue()); + else + val = Convert.ToInt16((ulong)((LongVariant)pop).GetValue()); + break; + } + val = (short)((LongVariant)pop).GetValue(); + break; + default: + // это нужно будет заменить на соотв. msil-код + var dyn = new DynamicMethod(String.Empty, typeof(short), new[] { typeof(object) }, typeof(void), true); + var gen = dyn.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(signed ? (ovf ? OpCodes.Conv_Ovf_I2 : OpCodes.Conv_I2) : OpCodes.Conv_Ovf_I2_Un); + gen.Emit(OpCodes.Ret); + val = (short)dyn.Invoke(null, new[] { pop.GetValueAbstract() }); + break; + } + var push = new ShortVariant(); + push.SetValue(val); + PushVariant(push); + } + + // Token: 0x060001FE RID: 510 RVA: 0x0000BFBC File Offset: 0x0000A1BC + private void Conv_i2_(VariantBase dummy) // \u0006\u2001\u2000 + { + Conv_i2(false, true); + } + + // Token: 0x060002A8 RID: 680 RVA: 0x00012D2C File Offset: 0x00010F2C + private void Conv_ovf_i4_(VariantBase dummy) // \u000F\u2000\u2000 + { + Conv_i4(true, true); + } + + private void Conv_i8(bool ovf, bool signed) + { + var pop = PopVariant(); + long val; + switch (pop.GetTypeCode()) + { + case VariantBase.Vtc.Tc5Enum: + var v = VariantBase.SignedVariantFromEnum((EnumVariant)pop).GetValueAbstract(); + if (!signed && ovf && Marshal.SizeOf(v) > 4) + val = checked((long)(ulong)Convert.ToInt64(v)); + else + val = (signed || Marshal.SizeOf(v) > 4) ? Convert.ToInt64(v) : + (uint)(ulong)Convert.ToInt64(v); + break; + case VariantBase.Vtc.Tc19Int: + int iv = ((IntVariant)pop).GetValue(); + if (signed) + val = iv; + else + val = (long)(uint)iv; + break; + case VariantBase.Vtc.Tc21Double: + if (ovf) + { + val = checked((long)((DoubleVariant)pop).GetValue()); + break; + } + val = (long)((DoubleVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc8Float: + if (ovf) + { + val = checked((long)((FloatVariant)pop).GetValue()); + break; + } + val = (long)((FloatVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc24Long: + if (ovf) + { + if (signed) + val = ((LongVariant)pop).GetValue(); + else + val = Convert.ToInt64((ulong)((LongVariant)pop).GetValue()); + break; + } + val = ((LongVariant)pop).GetValue(); + break; + default: + // это нужно будет заменить на соотв. msil-код + var dyn = new DynamicMethod(String.Empty, typeof(long), new[] { typeof(object) }, typeof(void), true); + var gen = dyn.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(signed ? (ovf ? OpCodes.Conv_Ovf_I8 : OpCodes.Conv_I8) : OpCodes.Conv_Ovf_I8_Un); + gen.Emit(OpCodes.Ret); + val = (long)dyn.Invoke(null, new[] { pop.GetValueAbstract() }); + break; + } + var push = new LongVariant(); + push.SetValue(val); + PushVariant(push); + } + + // Token: 0x06000219 RID: 537 RVA: 0x0000C824 File Offset: 0x0000AA24 + private void Conv_ovf_i8_(VariantBase dummy) // \u0008\u2002\u2000 + { + Conv_i8(true, true); + } + + private void Conv_i1(bool ovf, bool signed) + { + var pop = PopVariant(); + sbyte val; + switch (pop.GetTypeCode()) + { + case VariantBase.Vtc.Tc5Enum: + if (ovf) + { + var v = VariantBase.SignedVariantFromEnum((EnumVariant)pop).GetValueAbstract(); + val = signed ? Convert.ToSByte(v) : Convert.ToSByte((ulong)Convert.ToInt64(v)); + break; + } + val = (sbyte)VariantBase.SignedLongFromEnum((EnumVariant)pop); + break; + case VariantBase.Vtc.Tc19Int: + if (ovf && !signed) + { + val = Convert.ToSByte((uint)((IntVariant)pop).GetValue()); + break; + } + val = ovf ? Convert.ToSByte(((IntVariant)pop).GetValue()) : (sbyte)((IntVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc21Double: + if (ovf) + { + val = signed ? checked((sbyte)((DoubleVariant)pop).GetValue()) : + (IntPtr.Size == 4 ? Convert.ToSByte(Convert.ToByte(((DoubleVariant)pop).GetValue())) : + Convert.ToSByte((long)((DoubleVariant)pop).GetValue())); + break; + } + val = (sbyte)((DoubleVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc8Float: + if (ovf) + { + val = signed ? checked((sbyte)((FloatVariant)pop).GetValue()) : + (IntPtr.Size == 4 ? Convert.ToSByte(Convert.ToByte(((FloatVariant)pop).GetValue())) : + Convert.ToSByte((long)((FloatVariant)pop).GetValue())); + break; + } + val = (sbyte)((FloatVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc24Long: + if (ovf) + { + if (signed) + val = checked((sbyte)((LongVariant)pop).GetValue()); + else + val = Convert.ToSByte((ulong)((LongVariant)pop).GetValue()); + break; + } + val = (sbyte)((LongVariant)pop).GetValue(); + break; + default: + // это нужно будет заменить на соотв. msil-код + var dyn = new DynamicMethod(String.Empty, typeof(SByte), new[] { typeof(object) }, typeof(void), true); + var gen = dyn.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(signed ? (ovf ? OpCodes.Conv_Ovf_I1 : OpCodes.Conv_I1) : OpCodes.Conv_Ovf_I1_Un); + gen.Emit(OpCodes.Ret); + val = (sbyte)dyn.Invoke(null, new[] { pop.GetValueAbstract() }); + break; + } + var push = new SbyteVariant(); + push.SetValue(val); + PushVariant(push); + } + + // Token: 0x060002A6 RID: 678 RVA: 0x00012CD0 File Offset: 0x00010ED0 + private void Conv_i1_(VariantBase dummy) // \u000E\u2006 + { + Conv_i1(false, true); + } + + // Token: 0x06000285 RID: 645 RVA: 0x00011EF0 File Offset: 0x000100F0 + private void Conv_ovf_i2_(VariantBase dummy) // \u0002\u2000\u2001 + { + Conv_i2(true, true); + } + + // Token: 0x0600018D RID: 397 RVA: 0x000083F8 File Offset: 0x000065F8 + private void Conv_u_(VariantBase dummy) // \u000F\u2003\u2001 + { + Conv_u(false, true); + } + + // Token: 0x060001EF RID: 495 RVA: 0x0000B658 File Offset: 0x00009858 + private void Conv_ovf_u_(VariantBase dummy) // \u0002\u2000 + { + Conv_u(true, true); + } + + // Token: 0x06000215 RID: 533 RVA: 0x0000C784 File Offset: 0x0000A984 + private void Conv_u1_(VariantBase dummy) // \u0008\u2002 + { + Conv_u1(false, true); + } + + // Token: 0x06000211 RID: 529 RVA: 0x0000C690 File Offset: 0x0000A890 + private void Conv_ovf_i_un_(VariantBase dummy) // \u000F + { + Conv_i(true, false); + } + + // Token: 0x06000229 RID: 553 RVA: 0x0000F56C File Offset: 0x0000D76C + private void Conv_i4_(VariantBase dummy) // \u0003\u2005\u2000 + { + Conv_i4(false, true); + } + + private void Conv_ovf_i8_un_(VariantBase dummy) + { + Conv_i8(true, false); + } + + // Token: 0x06000253 RID: 595 RVA: 0x00010790 File Offset: 0x0000E990 + private void Conv_ovf_u4_un_(VariantBase dummy) // \u0002\u2009\u2000 + { + Conv_u4(true, false); + } + + // Token: 0x06000284 RID: 644 RVA: 0x00011EE4 File Offset: 0x000100E4 + private void Conv_i8_(VariantBase dummy) // \u0003\u2006\u2000 + { + Conv_i8(false, true); + } + + // Token: 0x0600028A RID: 650 RVA: 0x000121B8 File Offset: 0x000103B8 + private void Conv_ovf_u_un_(VariantBase dummy) // \u000F\u200B + { + Conv_u(true, false); + } + + private unsafe void Conv_i(bool ovf, bool signed) + { + var pop = PopVariant(); + var push = new IntPtrVariant(); + long val; + var tc = pop.GetTypeCode(); + if (tc == VariantBase.Vtc.Tc21Double || tc == VariantBase.Vtc.Tc8Float) + signed = true; + long maxVal = long.MaxValue, minVal = signed ? long.MinValue : 0; + if (IntPtr.Size == 4) + { + maxVal = signed ? Int32.MaxValue : UInt32.MaxValue; + minVal = signed ? Int32.MinValue : 0; + } + switch (tc) + { + case VariantBase.Vtc.Tc5Enum: + var v = VariantBase.SignedVariantFromEnum((EnumVariant)pop).GetValueAbstract(); + if (IntPtr.Size == 4) + { + if (ovf) val = Convert.ToInt32(v); + else val = (int)Convert.ToInt64(v); + } + else + { + val = (signed || Marshal.SizeOf(v) > 4 || !ovf) ? Convert.ToInt64(v) : + (uint)(ulong)Convert.ToInt64(v); + } + break; + case VariantBase.Vtc.Tc19Int: + int iv = ((IntVariant) pop).GetValue(); + if (IntPtr.Size == 4 || signed) + val = iv; + else + val = (long)(uint)iv; + break; + case VariantBase.Vtc.Tc21Double: + { + double dv = ((DoubleVariant)pop).GetValue(); + if (dv <= maxVal && dv >= minVal) + val = (long)dv; + else + { + if (ovf) throw new OverflowException(); + val = (IntPtr.Size == 4) ? Int32.MinValue : Int64.MinValue; // не мусор ли? + } + } + break; + case VariantBase.Vtc.Tc8Float: + { + double dv = (double) ((FloatVariant) pop).GetValue(); + if (dv <= maxVal && dv >= minVal) + val = (long) dv; + else + { + if (ovf) throw new OverflowException(); + val = (IntPtr.Size == 4) ? Int32.MinValue : Int64.MinValue; // не мусор ли? + } + } + break; + case VariantBase.Vtc.Tc24Long: + val = ((LongVariant)pop).GetValue(); + break; + default: + // это нужно будет заменить на соотв. msil-код + var dyn = new DynamicMethod(String.Empty, typeof(IntPtr), new[] { typeof(object) }, typeof(void), true); + var gen = dyn.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(signed ? (ovf ? OpCodes.Conv_Ovf_I : OpCodes.Conv_I) : OpCodes.Conv_Ovf_I_Un); + gen.Emit(OpCodes.Ret); + push.SetValue(((IntPtr)dyn.Invoke(null, new[] { pop.GetValueAbstract() }))); + PushVariant(push); + return; + } + if ((ovf == false) || (val <= maxVal && val >= minVal)) + { + push.SetValue(new IntPtr((void*)val)); + PushVariant(push); + } else throw new OverflowException(); + } + private unsafe void Conv_u(bool ovf, bool signed) + { + var pop = PopVariant(); + var push = new UIntPtrVariant(); + ulong val, maxVal = (IntPtr.Size == 4) ? UInt32.MaxValue : UInt64.MaxValue; + var tc = pop.GetTypeCode(); + switch (tc) + { + case VariantBase.Vtc.Tc5Enum: + var v = VariantBase.SignedVariantFromEnum((EnumVariant)pop).GetValueAbstract(); + if (IntPtr.Size == 4) + { + if (ovf) val = signed ? + Convert.ToUInt64(v) : + (Marshal.SizeOf(v) > 4) ? (ulong)Convert.ToInt64(v) : (uint)Convert.ToInt32(v); + else val = (uint)Convert.ToInt64(v); + } + else + { + val = (Marshal.SizeOf(v) > 4) ? + ((ovf && signed) ? Convert.ToUInt64(Convert.ToInt64(v)) : (ulong)Convert.ToInt64(v)) : + ((ovf && signed) ? Convert.ToUInt32(Convert.ToInt32(v)) : (uint)Convert.ToInt32(v)); + } + break; + case VariantBase.Vtc.Tc19Int: + int iv = ((IntVariant)pop).GetValue(); + if (ovf && signed && iv < 0) throw new OverflowException(); + val = (uint)iv; + break; + case VariantBase.Vtc.Tc21Double: + { + double dv = ((DoubleVariant)pop).GetValue(); + if (ovf && signed && dv < 0) throw new OverflowException(); + if (dv <= maxVal && (signed || dv >= 0)) + val = (ulong)dv; + else + { + if (ovf) throw new OverflowException(); + val = 0; // мусор, индульгируем + } + } + break; + case VariantBase.Vtc.Tc8Float: + { + double dv = (double)((FloatVariant)pop).GetValue(); + if (ovf && signed && dv < 0) throw new OverflowException(); + if (dv <= maxVal && (signed || dv >= 0)) + val = (ulong)dv; + else + { + if (ovf) throw new OverflowException(); + val = 0; // мусор, индульгируем + } + } + break; + case VariantBase.Vtc.Tc24Long: + long lv = ((LongVariant)pop).GetValue(); + if (ovf && signed && lv < 0) throw new OverflowException(); + val = (ulong) lv; + break; + default: + // это нужно будет заменить на соотв. msil-код + var dyn = new DynamicMethod(String.Empty, typeof(UIntPtr), new[] { typeof(object) }, typeof(void), true); + var gen = dyn.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(signed ? (ovf ? OpCodes.Conv_Ovf_U : OpCodes.Conv_U) : OpCodes.Conv_Ovf_U_Un); + gen.Emit(OpCodes.Ret); + push.SetValue(((UIntPtr)dyn.Invoke(null, new[] { pop.GetValueAbstract() }))); + PushVariant(push); + return; + } + if ((ovf == false) || (val <= maxVal)) + { + push.SetValue(new UIntPtr((void*)val)); + PushVariant(push); + } + else throw new OverflowException(); + } + + private void Conv_u8(bool ovf, bool signed) + { + var pop = PopVariant(); + ulong val; + switch (pop.GetTypeCode()) + { + case VariantBase.Vtc.Tc5Enum: + var v = VariantBase.SignedVariantFromEnum((EnumVariant)pop).GetValueAbstract(); + if(ovf && signed) + val = Convert.ToUInt64(v); + else + if (Marshal.SizeOf(v) > 4) + val = (ulong)Convert.ToInt64(v); + else + val = (uint)(ulong)Convert.ToInt64(v); + break; + case VariantBase.Vtc.Tc19Int: + int iv = ((IntVariant)pop).GetValue(); + val = ovf ? (signed ? checked((uint)iv) : (uint)iv) : (uint)iv; + break; + case VariantBase.Vtc.Tc21Double: + if (ovf) + { + val = checked((ulong)((DoubleVariant)pop).GetValue()); + break; + } + val = (ulong)((DoubleVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc8Float: + if (ovf) + { + val = checked((ulong)((FloatVariant)pop).GetValue()); + break; + } + val = (ulong)((FloatVariant)pop).GetValue(); + break; + case VariantBase.Vtc.Tc24Long: + if (ovf && signed) + val = Convert.ToUInt64(((LongVariant)pop).GetValue()); + else + val = (ulong)((LongVariant)pop).GetValue(); + break; + default: + // это нужно будет заменить на соотв. msil-код + var dyn = new DynamicMethod(String.Empty, typeof(ulong), new[] { typeof(object) }, typeof(void), true); + var gen = dyn.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(signed ? (ovf ? OpCodes.Conv_Ovf_U8 : OpCodes.Conv_U8) : OpCodes.Conv_Ovf_U8_Un); + gen.Emit(OpCodes.Ret); + val = (ulong)dyn.Invoke(null, new[] { pop.GetValueAbstract() }); + break; + } + var push = new UlongVariant(); + push.SetValue(val); + PushVariant(push); + } + + // Token: 0x06000204 RID: 516 RVA: 0x0000C19C File Offset: 0x0000A39C + private void Conv_u8_(VariantBase dummy) // \u0003\u2005 + { + Conv_u8(false, true); + } + + // Token: 0x0600020E RID: 526 RVA: 0x0000C58C File Offset: 0x0000A78C + private void Conv_ovf_u8_(VariantBase dummy) // \u0008\u2008\u2000 + { + Conv_u8(true, true); + } + + // Token: 0x06000208 RID: 520 RVA: 0x0000C43C File Offset: 0x0000A63C + private void Conv_ovf_i1_un_(VariantBase dummy) // \u0008 + { + Conv_i1(true, false); + } + + private void Conv_ovf_u1_un_(VariantBase dummy) + { + Conv_u1(true, false); + } + + // Token: 0x060001BB RID: 443 RVA: 0x000094E0 File Offset: 0x000076E0 + private void _u0006u2003u2001(VariantBase dummy) // \u0006\u2003\u2001 + { + } + + // Token: 0x060001BC RID: 444 RVA: 0x000094E4 File Offset: 0x000076E4 + private VariantBase[] CreateLocalVariables() // u0002 + { + var array = _methodHeader.LocalVarTypes; + var num = array.Length; + var ret = new VariantBase[num]; + for (var i = 0; i < num; i++) + { + ret[i] = VariantFactory.Convert(null, GetTypeById(array[i].TypeId)); + } + return ret; + } + + // Token: 0x060001C0 RID: 448 RVA: 0x0000958C File Offset: 0x0000778C + private MethodBase FindGenericMethod(VmMethodTokenInfo what) // \u0002 + { + var type = GetTypeById(what.Class.MetadataToken); + var bindingAttr = BF(what.IsStatic()); + var arg_32_0 = type.GetMember(what.Name, bindingAttr); + var array = arg_32_0; + var methodInfo = (from MethodInfo methodInfo2 in array + where methodInfo2.IsGenericMethodDefinition + let parameters = methodInfo2.GetParameters() + where + parameters.Length == what.Parameters.Length && + methodInfo2.GetGenericArguments().Length == what.GenericArguments.Length && + AreCompatible(methodInfo2.ReturnType, what.ReturnType) + where !parameters.Where((t1, j) => !AreCompatible(t1.ParameterType, what.Parameters[j])).Any() + select methodInfo2).FirstOrDefault(); + if (methodInfo == null) + { + throw new Exception(string.Format(StringDecryptor.GetString(-1550347247) /* Cannot bind method: {0}.{1} */, type.Name, what.Name)); + } + var array2 = new Type[what.GenericArguments.Length]; + for (var k = 0; k < array2.Length; k++) + { + array2[k] = GetTypeById(what.GenericArguments[k].MetadataToken); + } + return methodInfo.MakeGenericMethod(array2); + } + + // Token: 0x060001C2 RID: 450 RVA: 0x000097A0 File Offset: 0x000079A0 + private bool InvokeFilter(MethodBase mb, object obj, ref object result, object[] args) // \u0002 + { + var declaringType = mb.DeclaringType; + if (declaringType == null) + { + return false; + } + if (SimpleTypeHelper.IsNullableGeneric(declaringType)) + { + if (string.Equals(mb.Name, StringDecryptor.GetString(-1550345611) /* get_HasValue */, StringComparison.Ordinal)) + { + result = obj != null; + } + else if (string.Equals(mb.Name, StringDecryptor.GetString(-1550345722) /* get_Value */, StringComparison.Ordinal)) + { + if (obj == null) + { + //return ((bool?)null).Value; + throw new InvalidOperationException(); + } + result = obj; + } + else if (mb.Name.Equals(StringDecryptor.GetString(-1550345706) /* GetValueOrDefault */, StringComparison.Ordinal)) + { + if (obj == null) + { + /*u0005 =*/ Activator.CreateInstance(Nullable.GetUnderlyingType(mb.DeclaringType)); + } + result = obj; + } + else + { + if (obj != null || mb.IsStatic) + { + return false; + } + result = null; + } + return true; + } + if (declaringType == SimpleTypeHelper.TypedReferenceType) + { + var name = mb.Name; + var i = args.Length; + if (i != 1) + { + if (i == 2) + { + if (name == StringDecryptor.GetString(-1550345495) /* SetTypedReference */) + { + TypedReference.SetTypedReference((TypedReference)args[0], args[1]); + return true; + } + } + } + else + { + if (name == StringDecryptor.GetString(-1550345682) /* GetTargetType */) + { + result = TypedReference.GetTargetType((TypedReference)args[0]); + return true; + } + if (name == StringDecryptor.GetString(-1550345534) /* TargetTypeToken */) + { + result = TypedReference.TargetTypeToken((TypedReference)args[0]); + return true; + } + if (name == StringDecryptor.GetString(-1550345512) /* ToObject */) + { + result = TypedReference.ToObject((TypedReference)args[0]); + return true; + } + } + } + else if (declaringType == AssemblyType) + { + if (_callees != null && mb.Name == StringDecryptor.GetString(-1550345599) /* GetCallingAssembly */) + { + var array = _callees; + foreach (var t in array) + { + var assembly = t as Assembly; + if (assembly != null) + { + result = assembly; + return true; + } + } + } + } + else if (declaringType == MethodBaseType) + { + if (mb.Name == StringDecryptor.GetString(-1550345576) /* GetCurrentMethod */) + { + if (_callees != null) + { + var array = _callees; + foreach (var t in array) + { + var methodBase = t as MethodBase; + if (methodBase != null) + { + result = methodBase; + return true; + } + } + } + result = MethodBase.GetCurrentMethod(); + return true; + } + } + else if (declaringType.IsArray && declaringType.GetArrayRank() >= 2) + { + return RefToMdArrayItem(mb, obj, ref result, args); + } + return false; + } + + // Token: 0x060001C3 RID: 451 RVA: 0x000099F8 File Offset: 0x00007BF8 + private void Ldloca_s_(VariantBase vLocIdx) // \u0005\u2001\u2001 + { + var push = new LocalsIdxHolderVariant(); + push.SetValue(((ByteVariant)vLocIdx).GetValue()); + PushVariant(push); + } + + // Token: 0x060001C4 RID: 452 RVA: 0x00009A24 File Offset: 0x00007C24 + private void Ldind_i_(VariantBase dummy) // \u000E\u2004\u2000 + { + Ldind(IntPtrType); + } + + // Token: 0x060001C6 RID: 454 RVA: 0x00009D14 File Offset: 0x00007F14 + private void Stloc_(VariantBase vidx) // \u0008\u2006 + { + var idx = (UshortVariant)vidx; + PopToLocal(idx.GetValue()); + } + + // Token: 0x060001C7 RID: 455 RVA: 0x00009D34 File Offset: 0x00007F34 + private void Stfld_(VariantBase vFieldId) // \u0005\u200B + { + var fieldInfo = ResolveField(((IntVariant)vFieldId).GetValue()); + var val = PopVariant(); + var objRef = PopVariant(); + var obj = objRef.IsAddr() ? FetchByAddr(objRef).GetValueAbstract() : objRef.GetValueAbstract(); + if (obj == null) + { + throw new NullReferenceException(); + } + fieldInfo.SetValue(obj, VariantFactory.Convert(val.GetValueAbstract(), fieldInfo.FieldType).GetValueAbstract()); + if (objRef.IsAddr() && /*obj != null && */ obj.GetType().IsValueType) + { + AssignByReference(objRef, VariantFactory.Convert(obj, null)); + } + } + + // Token: 0x060001C8 RID: 456 RVA: 0x00009DD0 File Offset: 0x00007FD0 + /*private void u000Fu2004(VariantBase dummy) // \u000F\u2004 + { + }*/ + + // Token: 0x060001CB RID: 459 RVA: 0x00009E7C File Offset: 0x0000807C + private void Ldloc_s_(VariantBase vidx) // \u0002 + { + var idx = (ByteVariant)vidx; + PushVariant(_localVariables[idx.GetValue()].Clone()); + } + + // Token: 0x060001D1 RID: 465 RVA: 0x0000A328 File Offset: 0x00008528 + private void Stelem_ref_(VariantBase dummy) // \u0008\u200A + { + Stelem(SimpleTypeHelper.ObjectType); + } + + // Token: 0x060001D3 RID: 467 RVA: 0x0000A34C File Offset: 0x0000854C + private void Ldelem_u2_(VariantBase dummy) // \u000E\u2003\u2001 + { + Ldelem(typeof(ushort)); + } + + // Token: 0x060001D5 RID: 469 RVA: 0x0000A620 File Offset: 0x00008820 + private void Stind_i4_(VariantBase dummy) // \u0006\u2003\u2000 + { + Stind(); + } + + // Token: 0x060001D6 RID: 470 RVA: 0x0000A628 File Offset: 0x00008828 + private void Stind_i8_(VariantBase dummy) // \u0003\u2002\u2000 + { + Stind(); + } + + // Token: 0x060001DC RID: 476 RVA: 0x0000AAD8 File Offset: 0x00008CD8 + private void Stelem_i8_(VariantBase dummy) // \u0002\u200B\u2000 + { + var obj = PopVariant().GetValueAbstract(); + var idx = PopLong(); + var array = (Array)PopVariant().GetValueAbstract(); + var elementType = array.GetType().GetElementType(); + checked + { + if (elementType == typeof(long)) + { + ((long[])array)[(int)(IntPtr)idx] = (long)VariantFactory.Convert(obj, typeof(long)).GetValueAbstract(); + return; + } + if (elementType == typeof(ulong)) + { + ((ulong[])array)[(int)(IntPtr)idx] = (ulong)VariantFactory.Convert(obj, typeof(ulong)).GetValueAbstract(); + return; + } + if (elementType.IsEnum) + { + Stelem(elementType, obj, idx, array); + return; + } + Stelem(typeof(long), obj, idx, array); + } + } + + // Token: 0x060001DD RID: 477 RVA: 0x0000ABA8 File Offset: 0x00008DA8 + private void Stelem_i_(VariantBase dummy) // \u000F\u2006\u2000 + { + Stelem(IntPtrType); + } + + // Token: 0x060001DE RID: 478 RVA: 0x0000ABB8 File Offset: 0x00008DB8 + private void Ldelem_i8_(VariantBase dummy) // \u0006\u2000 + { + Ldelem(typeof(long)); + } + + // Token: 0x060001E0 RID: 480 RVA: 0x0000ABD0 File Offset: 0x00008DD0 + private void Ldc_i4_(VariantBase val) // \u0006\u2000\u2000 + { + PushVariant(val); + } + + // Token: 0x060001E2 RID: 482 RVA: 0x0000AC08 File Offset: 0x00008E08 + private void Ldarg_1_(VariantBase dummy) // \u0002\u2003\u2001 + { + PushVariant(_variantOutputArgs[1].Clone()); + } + + // Token: 0x060001E3 RID: 483 RVA: 0x0000AC24 File Offset: 0x00008E24 + private void Ret_(VariantBase dummy) // \u000E\u2005\u2000 + { + Ret(); + } + + // Token: 0x060001E8 RID: 488 RVA: 0x0000B10C File Offset: 0x0000930C + private void Stelem(Type arrType, object val, long idx, Array array) // \u0002 + { + array.SetValue(VariantFactory.Convert(val, arrType).GetValueAbstract(), idx); + } + + // Token: 0x060001E9 RID: 489 RVA: 0x0000B130 File Offset: 0x00009330 + [DebuggerNonUserCode] + private MethodBase FindMethodById(int methodId, UniversalTokenInfo methodToken) // \u0002 + { + MethodBase result = null; + lock (AllMetadataById) + { + //var flag = true; + object obj; + if (/*flag &&*/ AllMetadataById.TryGetValue(methodId, out obj)) + { + result = (MethodBase)obj; + } + else if (methodToken.IsVm == 0) + { + var methodBase = _module.ResolveMethod(methodToken.MetadataToken); + //if (flag) + { + AllMetadataById.Add(methodId, methodBase); + } + result = methodBase; + } + else + { + var mti = (VmMethodTokenInfo)methodToken.VmToken; + if (mti.IsGeneric()) + { + result = FindGenericMethod(mti); + } + else + { + var clsType = GetTypeById(mti.Class.MetadataToken); + var retType = GetTypeById(mti.ReturnType.MetadataToken); + var paramArray = new Type[mti.Parameters.Length]; + for (var i = 0; i < paramArray.Length; i++) + { + paramArray[i] = GetTypeById(mti.Parameters[i].MetadataToken); + } + /*if (type.IsGenericType) + { + flag = false; + }*/ + if (mti.Name == StringDecryptor.GetString(-1550347259) /* .ctor */) + { + var constructor = clsType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, CallingConventions.Any, paramArray, null); + if (constructor == null) + { + throw new Exception(); + } + if (!clsType.IsGenericType) + { + AllMetadataById.Add(methodId, constructor); + } + result = constructor; + } + else + { + var bindingAttr = BF(mti.IsStatic()); + try + { + result = clsType.GetMethod(mti.Name, bindingAttr, null, CallingConventions.Any, paramArray, null); + } + catch (AmbiguousMatchException) + { + var methods = clsType.GetMethods(bindingAttr); + foreach (var methodInfo in methods) + { + if (methodInfo.Name == mti.Name && methodInfo.ReturnType == retType) + { + var parameters = methodInfo.GetParameters(); + if (parameters.Length == paramArray.Length) + { + if (!(bool)paramArray.Where((t, k) => parameters[k].ParameterType != t).Any()) + { + result = methodInfo; + break; + } + } + } + } + } + if (result == null) + { + throw new Exception(string.Format(StringDecryptor.GetString(-1550347247) /* Cannot bind method: {0}.{1} */, clsType.Name, mti.Name)); + } + if (!clsType.IsGenericType) + { + AllMetadataById.Add(methodId, result); + } + } + } + } + } + return result; + } + + // Token: 0x060001EA RID: 490 RVA: 0x0000B3B8 File Offset: 0x000095B8 + private void Stloc_s_(VariantBase vidx) // \u000E\u2004 + { + var idx = (ByteVariant)vidx; + PopToLocal(idx.GetValue()); + } + + // Token: 0x060001EB RID: 491 RVA: 0x0000B3D8 File Offset: 0x000095D8 + private void LockIfInterlocked(ref BoolHolder wasLocked, MethodBase mb, bool dummy) // \u0002 + { + if (mb.DeclaringType == typeof(Interlocked) && mb.IsStatic) + { + var name = mb.Name; + if (name == StringDecryptor.GetString(-1550347213) /* Add */ || name == StringDecryptor.GetString(-1550347203) /* CompareExchange */ || name == StringDecryptor.GetString(-1550347053) /* Decrement */ || name == StringDecryptor.GetString(-1550347037) /* Exchange */ || name == StringDecryptor.GetString(-1550347024) /* Increment */ || name == StringDecryptor.GetString(-1550347136) /* Read*/) + { + Monitor.Enter(InterlockedLock); + wasLocked.Val = true; + } + } + } + + // Token: 0x060001EC RID: 492 RVA: 0x0000B4A0 File Offset: 0x000096A0 + private void Box_(VariantBase vTypeId) // \u0003\u2009\u2000 + { + var type = GetTypeById(((IntVariant)vTypeId).GetValue()); + var push = VariantFactory.Convert(PopVariant().GetValueAbstract(), type); + push.SetVariantType(type); + PushVariant(push); + } + + // Token: 0x060001F1 RID: 497 RVA: 0x0000B690 File Offset: 0x00009890 + private void Sizeof_(VariantBase vTypeId) // \u000E\u2001\u2001 + { + var t = GetTypeById(((IntVariant)vTypeId).GetValue()); + var iv = new IntVariant(); + iv.SetValue(Marshal.SizeOf(t)); + PushVariant(iv); + } + + // Token: 0x060001F3 RID: 499 RVA: 0x0000B758 File Offset: 0x00009958 + private void Ldelem_i_(VariantBase dummy) // \u000F\u2000 + { + Ldelem(IntPtrType); + } + + // Token: 0x060001F4 RID: 500 RVA: 0x0000B768 File Offset: 0x00009968 + private void InternalInvoke() // \u0002 + { + try + { + LoopUntilRet(); + } + catch (Exception ex) + { + OnException(ex, 0u); + LoopUntilRet(); + } + } + + // Token: 0x060001F5 RID: 501 RVA: 0x0000B7A0 File Offset: 0x000099A0 + private MethodBase GenerateDynamicCall(MethodBase mb, bool mayVirtual) // \u0002 + { + MethodBase result; + lock (DynamicMethods) + { + DynamicMethod dynamicMethod; + if (DynamicMethods.TryGetValue(mb, out dynamicMethod)) + { + result = dynamicMethod; + } + else + { + var methodInfo = mb as MethodInfo; + var returnType = methodInfo?.ReturnType ?? VoidType; + var parameters = mb.GetParameters(); + Type[] array; + if (mb.IsStatic) + { + array = new Type[parameters.Length]; + for (var i = 0; i < parameters.Length; i++) + { + array[i] = parameters[i].ParameterType; + } + } + else + { + array = new Type[parameters.Length + 1]; + var type = mb.DeclaringType; + if (type.IsValueType) + { + type = type.MakeByRefType(); + mayVirtual = false; + } + array[0] = type; + for (var j = 0; j < parameters.Length; j++) + { + array[j + 1] = parameters[j].ParameterType; + } + } + /*if (_alwaysFalse) + { + dynamicMethod = new DynamicMethod(string.Empty, returnType, array, true); + } + if (dynamicMethod == null)*/ + { + dynamicMethod = new DynamicMethod(string.Empty, returnType, array, GetTypeById(_methodHeader.ClassId), true); + } + var iLGenerator = dynamicMethod.GetILGenerator(); + for (var k = 0; k < array.Length; k++) + { + iLGenerator.Emit(OpCodes.Ldarg, k); + } + var constructorInfo = mb as ConstructorInfo; + if (constructorInfo != null) + { + iLGenerator.Emit(mayVirtual ? OpCodes.Callvirt : OpCodes.Call, constructorInfo); + } + else + { + iLGenerator.Emit(mayVirtual ? OpCodes.Callvirt : OpCodes.Call, (MethodInfo)mb); + } + iLGenerator.Emit(OpCodes.Ret); + DynamicMethods.Add(mb, dynamicMethod); + result = dynamicMethod; + } + } + return result; + } + + // Token: 0x060001F7 RID: 503 RVA: 0x0000B9EC File Offset: 0x00009BEC + private void Ldelem_i4_(VariantBase dummy) // \u000E\u2007 + { + Ldelem(typeof(int)); + } + + // Token: 0x060001FD RID: 509 RVA: 0x0000BD88 File Offset: 0x00009F88 + private void Invoke(int pos, Type[] methodGenericArgs, Type[] classGenericArgs, bool mayVirtual) // \u0002 + { + _srcVirtualizedStreamReader.BaseStream.Seek(pos, SeekOrigin.Begin); + DoNothing(_srcVirtualizedStreamReader); + var u0006 = ReadMethodHeader(_srcVirtualizedStreamReader); + var num = u0006.ArgsTypeToOutput.Length; + var array = new object[num]; + var array2 = new VariantBase[num]; + if (_currentClass != null & mayVirtual) + { + var num2 = u0006.IsStatic() ? 0 : 1; + var array3 = new Type[num - num2]; + for (var i = num - 1; i >= num2; i--) + { + array3[i] = GetTypeById(u0006.ArgsTypeToOutput[i].TypeId); + } + var method = _currentClass.GetMethod(u0006.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.GetProperty | BindingFlags.SetProperty, null, array3, null); + _currentClass = null; + if (method != null) + { + GenerateDynamicCall(method, true); + return; + } + } + for (var j = num - 1; j >= 0; j--) + { + var u000F = PopVariant(); + array2[j] = u000F; + if (u000F.IsAddr()) + { + u000F = FetchByAddr(u000F); + } + if (u000F.GetVariantType() != null) + { + u000F = VariantFactory.Convert(null, u000F.GetVariantType()).CopyFrom(u000F); + } + var u000F2 = VariantFactory.Convert(null, GetTypeById(u0006.ArgsTypeToOutput[j].TypeId)).CopyFrom(u000F); + array[j] = u000F2.GetValueAbstract(); + if (j == 0 & mayVirtual && !u0006.IsStatic() && array[j] == null) + { + throw new NullReferenceException(); + } + } + var executor = new VmExecutor(_instrCodesDb); + var callees = new object[] + { + _module.Assembly + }; + object obj; + try + { + obj = executor.Invoke(_srcVirtualizedStream, pos, array, methodGenericArgs, classGenericArgs, callees); + } + finally + { + for (var k = 0; k < array2.Length; k++) + { + var u000F3 = array2[k]; + if (u000F3.IsAddr()) + { + var obj2 = array[k]; + AssignByReference(u000F3, VariantFactory.Convert(obj2, null)); + } + } + } + var type = executor.GetTypeById(executor._methodHeader.ReturnTypeId); + if (type != VoidType) + { + PushVariant(VariantFactory.Convert(obj, type)); + } + } + + // Token: 0x06000202 RID: 514 RVA: 0x0000C150 File Offset: 0x0000A350 + public static object CreateValueTypeInstance(Type t) // \u0002 + { + if (t.IsValueType) + { + return Activator.CreateInstance(t); + } + return null; + } + + // Token: 0x0600020B RID: 523 RVA: 0x0000C51C File Offset: 0x0000A71C + private void Ldc_r4_(VariantBase val) // \u0003\u200B\u2000 + { + PushVariant(val); + } + + // Token: 0x0600020D RID: 525 RVA: 0x0000C550 File Offset: 0x0000A750 + private void Stelem(Type t) // \u0003 + { + var obj = PopVariant().GetValueAbstract(); + var idx = PopLong(); + var array = (Array)PopVariant().GetValueAbstract(); + Stelem(t, obj, idx, array); + } + + // Token: 0x06000210 RID: 528 RVA: 0x0000C5C4 File Offset: 0x0000A7C4 + private void Ldvirtftn_(VariantBase vMethodId) // \u0003\u200A + { + var methodBase = FindMethodById(((IntVariant)vMethodId).GetValue()); + var declaringType = methodBase.DeclaringType; + var type = PopVariant().GetValueAbstract().GetType(); + var parameters = methodBase.GetParameters(); + var paramTypes = new Type[parameters.Length]; + for (var i = 0; i < parameters.Length; i++) + { + paramTypes[i] = parameters[i].ParameterType; + } + while (type != null && type != declaringType) + { + var method = type.GetMethod(methodBase.Name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.SetProperty | BindingFlags.ExactBinding, null, CallingConventions.Any, paramTypes, null); + if (method != null && method.GetBaseDefinition() == methodBase) + { + methodBase = method; + break; + } + type = type.BaseType; + } + var push = new MethodVariant(); + push.SetValue(methodBase); + PushVariant(push); + } + + // Token: 0x06000213 RID: 531 RVA: 0x0000C750 File Offset: 0x0000A950 + private void Ldind_u4_(VariantBase dummy) // \u000E\u2002\u2001 + { + Ldind(typeof(uint)); + } + + // Token: 0x06000218 RID: 536 RVA: 0x0000C810 File Offset: 0x0000AA10 + private void Ldind_i2_(VariantBase dummy) // \u0003\u2002\u2001 + { + Ldind(typeof(short)); + } + + // Token: 0x0600021A RID: 538 RVA: 0x0000C830 File Offset: 0x0000AA30 + private void Ldind_u2_(VariantBase dummy) // \u000F\u2001\u2001 + { + Ldind(typeof(ushort)); + } + + // Token: 0x0600021B RID: 539 RVA: 0x0000C844 File Offset: 0x0000AA44 + private void Break_(VariantBase dummy) // \u0005\u2002 + { + Debugger.Break(); + } + + // Token: 0x0600021D RID: 541 RVA: 0x0000C878 File Offset: 0x0000AA78 + private void Ldc_i4_m1_(VariantBase dummy) // \u0002\u2005 + { + var iv = new IntVariant(); + iv.SetValue(-1); + PushVariant(iv); + } + + // Token: 0x0600021E RID: 542 RVA: 0x0000C88C File Offset: 0x0000AA8C + private void ExecuteNextInstruction() // \u0002\u2000 + { + try + { + TryExecuteNextInstruction(); + } + catch (Exception ex) + { + OnException(ex, 0u); + } + } + + // Token: 0x06000220 RID: 544 RVA: 0x0000F07C File Offset: 0x0000D27C + private void OnException(object ex, uint pos) // \u0002 + { + _wasException = ex != null; + _exception = ex; + if (_wasException) + { + _ehStack.Clear(); + } + if (!_wasException) + { + _ehStack.PushBack(new ExcHandlerFrame { Pos = pos }); + } + foreach (var catchBlock in _catchBlocks) + { + if (PosInRange(_myBufferPos, catchBlock.Start, catchBlock.Len)) + { + switch (catchBlock.Kind) + { + case 0: + if (_wasException) + { + var type = ex.GetType(); + var type2 = GetTypeById(catchBlock.ExcTypeId); + if (type == type2 || type.IsSubclassOf(type2)) + { + _ehStack.PushBack(new ExcHandlerFrame + { + Pos = catchBlock.Pos, + Exception = ex + }); + _wasException = false; + } + } + break; + case 1: + if (_wasException) + { + _ehStack.PushBack(new ExcHandlerFrame { Pos = catchBlock.Pos }); + } + break; + case 2: + if (_wasException || !PosInRange((long)(ulong)pos, catchBlock.Start, catchBlock.Len)) + { + _ehStack.PushBack(new ExcHandlerFrame { Pos = catchBlock.Pos }); + } + break; + case 4: + if (_wasException) + { + _ehStack.PushBack(new ExcHandlerFrame + { + Pos = catchBlock.PosKind4, + Exception = ex + }); + } + break; + } + } + } + ExecuteExceptionHandler(); + } + + // Token: 0x06000221 RID: 545 RVA: 0x0000F210 File Offset: 0x0000D410 + private void Stloc_0_(VariantBase dummy) // \u0008\u2003 + { + PopToLocal(0); + } + + // Token: 0x06000222 RID: 546 RVA: 0x0000F21C File Offset: 0x0000D41C + private void Ldind_ref_(VariantBase dummy) // \u0003\u2003\u2001 + { + Ldind(SimpleTypeHelper.ObjectType); + } + + // Token: 0x06000223 RID: 547 RVA: 0x0000F22C File Offset: 0x0000D42C + private void Stind_r4_(VariantBase dummy) // \u0006\u2006 + { + Stind(); + } + + // Token: 0x06000224 RID: 548 RVA: 0x0000F234 File Offset: 0x0000D434 + private void Newarr_(VariantBase vTypeId) // \u0002\u2001\u2001 + { + var vLength = PopVariant(); + var ivLength = vLength as IntVariant; + int length; + if (ivLength != null) + { + length = ivLength.GetValue(); + } + else + { + var ipvLength = vLength as IntPtrVariant; + if (ipvLength != null) + { + length = ipvLength.GetValue().ToInt32(); + } + else + { + var uipvLength = vLength as UIntPtrVariant; + if (uipvLength == null) + { + throw new Exception(); + } + length = (int)uipvLength.GetValue().ToUInt32(); + } + } + var array = Array.CreateInstance(GetTypeById(((IntVariant)vTypeId).GetValue()), length); + var push = new ArrayVariant(); + push.SetValue(array); + PushVariant(push); + } + + // Token: 0x06000226 RID: 550 RVA: 0x0000F308 File Offset: 0x0000D508 + private bool RefToMdArrayItem(MethodBase mb, object array, ref object result, object[] oidxs) // \u0003 + { + if (!mb.IsStatic && mb.Name == StringDecryptor.GetString(-1550345964) /* Address */) + { + var methodInfo = mb as MethodInfo; + if (methodInfo != null) + { + var type = methodInfo.ReturnType; + if (type.IsByRef) + { + type = type.GetElementType(); + var num = oidxs.Length; + if (num >= 1 && oidxs[0] is int) + { + var idxs = new int[num]; + for (var i = 0; i < num; i++) + { + idxs[i] = (int)oidxs[i]; + } + var val = new MdArrayValueVariant(); + val.SetArray((Array)array); + val.SetIndexes(idxs); + val.SetHeldType(type); + result = val; + return true; + } + } + } + } + return false; + } + + // Token: 0x0600022C RID: 556 RVA: 0x0000F86C File Offset: 0x0000DA6C + private void Stelem_r4_(VariantBase dummy) // \u0005\u200A + { + Stelem(typeof(float)); + } + + // Token: 0x0600022E RID: 558 RVA: 0x0000F8AC File Offset: 0x0000DAAC + private void Ldarg_2_(VariantBase dummy) // \u0006\u2003 + { + PushVariant(_variantOutputArgs[2].Clone()); + } + + // Token: 0x06000230 RID: 560 RVA: 0x0000F8DC File Offset: 0x0000DADC + private void Not_(VariantBase dummy) // \u0008\u2002\u2001 + { + PushVariant(Not(PopVariant())); + } + + // Token: 0x06000232 RID: 562 RVA: 0x0000F914 File Offset: 0x0000DB14 + private void Ldind_i1_(VariantBase dummy) // \u000F\u2005\u2000 + { + Ldind(typeof(sbyte)); + } + + // Token: 0x06000233 RID: 563 RVA: 0x0000F928 File Offset: 0x0000DB28 + private void Stloc_2_(VariantBase dummy) // \u000F\u2009 + { + PopToLocal(2); + } + + // Token: 0x06000235 RID: 565 RVA: 0x0000F96C File Offset: 0x0000DB6C + private void Stloc_1_(VariantBase dummy) // \u000E\u2009\u2000 + { + PopToLocal(1); + } + + // Token: 0x06000236 RID: 566 RVA: 0x0000F978 File Offset: 0x0000DB78 + private void Pop_(VariantBase dummy) // \u0003 + { + PopVariant(); + } + + // Token: 0x0600023A RID: 570 RVA: 0x0000F9D4 File Offset: 0x0000DBD4 + private void Ldc_r8_(VariantBase val) // \u0005\u200B\u2000 + { + PushVariant(val); + } + + // Token: 0x0600023F RID: 575 RVA: 0x0000FDF4 File Offset: 0x0000DFF4 + private void Ldelem_r4_(VariantBase dummy) // \u0008\u200B + { + Ldelem(typeof(float)); + } + + // Token: 0x06000240 RID: 576 RVA: 0x0000FE08 File Offset: 0x0000E008 + private void UnlockInterlockedIfAny(ref BoolHolder wasLocked) // \u0002 + { + if (wasLocked.Val) + { + Monitor.Exit(InterlockedLock); + } + } + + // Token: 0x06000241 RID: 577 RVA: 0x0000FE1C File Offset: 0x0000E01C + private void Ldarg_0_(VariantBase dummy) // \u0003\u2007 + { + PushVariant(_variantOutputArgs[0].Clone()); + } + + // Token: 0x06000245 RID: 581 RVA: 0x00010198 File Offset: 0x0000E398 + private VariantBase Not(VariantBase val) // \u0005 + { + switch (val.GetTypeCode()) + { + case VariantBase.Vtc.Tc19Int: + var iv = new IntVariant(); + iv.SetValue(~((IntVariant)val).GetValue()); + return iv; + case VariantBase.Vtc.Tc24Long: + var lv = new LongVariant(); + lv.SetValue(~((LongVariant)val).GetValue()); + return lv; + case VariantBase.Vtc.Tc5Enum: + var underlyingType = Enum.GetUnderlyingType(val.GetValueAbstract().GetType()); + if (underlyingType == typeof(ulong)) + { + var ret = new UlongVariant(); + ret.SetValue(~Convert.ToUInt64(val.GetValueAbstract())); + return ret; + } + if (underlyingType == typeof(long)) + { + var ret = new LongVariant(); + ret.SetValue(~Convert.ToInt64(val.GetValueAbstract())); + return ret; + } + if (underlyingType == typeof(uint)) + { + var ret = new UintVariant(); + ret.SetValue(~Convert.ToUInt32(val.GetValueAbstract())); + return ret; + } + var result = new IntVariant(); + result.SetValue(~Convert.ToInt32(val.GetValueAbstract())); + return result; + case VariantBase.Vtc.Tc21Double: + if (IntPtr.Size == 4) + { + var ret = new DoubleVariant(); + ret.SetValue(double.NaN); + return ret; + } + break; + case VariantBase.Vtc.Tc8Float: + if (IntPtr.Size == 4) + { + var ret = new FloatVariant(); + ret.SetValue(float.NaN); + return ret; + } + break; + case VariantBase.Vtc.Tc18Object: + // это нужно будет заменить на соотв. msil-код + var dyn = new DynamicMethod(String.Empty, typeof(IntPtr), new[] { typeof(object) }, typeof(void), true); + var gen = dyn.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(OpCodes.Not); + gen.Emit(OpCodes.Ret); + var oret = new IntPtrVariant(); + ((IntPtrVariant)oret).SetValue(((IntPtr)dyn.Invoke(null, new[] { val.GetValueAbstract() }))); + return oret; + } + throw new InvalidProgramException(); + } + + // Token: 0x06000246 RID: 582 RVA: 0x0001025C File Offset: 0x0000E45C + private void Ldind_i8_(VariantBase dummy) // \u0005\u2006 + { + Ldind(typeof(long)); + } + + // Token: 0x06000247 RID: 583 RVA: 0x00010270 File Offset: 0x0000E470 + private void Clt_(VariantBase dummy) // \u0002\u2004\u2001 + { + var v2 = PopVariant(); + var v1 = PopVariant(); + var push = new IntVariant(); + push.SetValue(UniCompare(v1, v2, ComparisonKind.LT, false) ? 1 : 0); + PushVariant(push); + } + + // Token: 0x06000249 RID: 585 RVA: 0x00010348 File Offset: 0x0000E548 + private void Nop_(VariantBase dummy) // \u0005\u2005 + { + } + + // Token: 0x0600024B RID: 587 RVA: 0x00010498 File Offset: 0x0000E698 + private void TryExecuteNextInstruction() // \u000E + { + var key = _myBufferReader.ReadInt32(); + VmInstr instr; + if (!_vmInstrDb.TryGetValue(key, out instr)) + { + throw new InvalidOperationException(StringDecryptor.GetString(-1550345644) /* Unsupported instruction. */); + } + instr.Func(ReadOperand(_myBufferReader, instr.Id.OperandType)); + _myBufferPos = _myBufferReader.GetBuffer().GetPos(); + } + + // Token: 0x0600024E RID: 590 RVA: 0x000105B4 File Offset: 0x0000E7B4 + private void Stelem_i1_(VariantBase dummy) // \u0002\u2003 + { + var obj = PopVariant().GetValueAbstract(); + var idx = PopLong(); + var array = (Array)PopVariant().GetValueAbstract(); + var elementType = array.GetType().GetElementType(); + checked + { + if (elementType == typeof(sbyte)) + { + ((sbyte[])array)[(int)(IntPtr)idx] = (sbyte)VariantFactory.Convert(obj, typeof(sbyte)).GetValueAbstract(); + return; + } + if (elementType == typeof(byte)) + { + ((byte[])array)[(int)(IntPtr)idx] = (byte)VariantFactory.Convert(obj, typeof(byte)).GetValueAbstract(); + return; + } + if (elementType == typeof(bool)) + { + ((bool[])array)[(int)(IntPtr)idx] = (bool)VariantFactory.Convert(obj, typeof(bool)).GetValueAbstract(); + return; + } + if (elementType.IsEnum) + { + Stelem(elementType, obj, idx, array); + return; + } + Stelem(typeof(sbyte), obj, idx, array); + } + } + + // Token: 0x0600024F RID: 591 RVA: 0x000106B8 File Offset: 0x0000E8B8 + private void Starg_s_(VariantBase vidx) // \u000E\u2007\u2000 + { + var idx = (ByteVariant)vidx; + _variantOutputArgs[idx.GetValue()].CopyFrom(PopVariant()); + } + + // Token: 0x06000251 RID: 593 RVA: 0x00010748 File Offset: 0x0000E948 + private void Ldlen_(VariantBase dummy) // \u000E\u200B\u2000 + { + var array = (Array)PopVariant().GetValueAbstract(); + var len = new IntVariant(); + len.SetValue(array.Length); + PushVariant(len); + } + + // Token: 0x06000256 RID: 598 RVA: 0x00010948 File Offset: 0x0000EB48 + private void Ldelem_i2_(VariantBase dummy) // \u0008\u2000 + { + Ldelem(typeof(short)); + } + + // Token: 0x06000257 RID: 599 RVA: 0x0001095C File Offset: 0x0000EB5C + private void Ldarg_(VariantBase vidx) // \u000E\u2000\u2000 + { + var idx = (UshortVariant)vidx; + PushVariant(_variantOutputArgs[idx.GetValue()].Clone()); + } + + // Token: 0x06000258 RID: 600 RVA: 0x0001098C File Offset: 0x0000EB8C + private void Clt_un_(VariantBase dummy) // \u0003\u2000\u2001 + { + var v2 = PopVariant(); + var v1 = PopVariant(); + var push = new IntVariant(); + push.SetValue(UniCompare(v1, v2, ComparisonKind.LT, true) ? 1 : 0); + PushVariant(push); + } + + // Token: 0x06000259 RID: 601 RVA: 0x000109C8 File Offset: 0x0000EBC8 + private void Dup_(VariantBase dummy) // \u0002\u2006\u2000 + { + var v = PopVariant(); + PushVariant(v); + PushVariant(v.Clone()); + } + + // Token: 0x0600025A RID: 602 RVA: 0x000109F4 File Offset: 0x0000EBF4 + [Conditional("DEBUG")] + private void DoNothing(object dummy) // \u0002 + { + } + + // Token: 0x0600025B RID: 603 RVA: 0x000109F8 File Offset: 0x0000EBF8 + private VariantBase[] ArgsToVariantOutputArgs(object[] args) // u0002 + { + var methodHeaderArgsTypeToOutput = _methodHeader.ArgsTypeToOutput; + var num = methodHeaderArgsTypeToOutput.Length; + var retArgs = new VariantBase[num]; + for (var i = 0; i < num; i++) + { + var obj = args[i]; + var type = GetTypeById(methodHeaderArgsTypeToOutput[i].TypeId); + var type2 = ElementedTypeHelper.TryGoToPointerOrReferenceElementType(type); + Type type3; + if (type2 == SimpleTypeHelper.ObjectType || SimpleTypeHelper.IsNullableGeneric(type2)) + { + type3 = type; + } + else + { + type3 = obj?.GetType() ?? type; + } + if (obj != null && !type.IsAssignableFrom(type3) && type.IsByRef && !type.GetElementType().IsAssignableFrom(type3)) + { + throw new ArgumentException(string.Format(StringDecryptor.GetString(-1550345390) /* Object of type {0} cannot be converted to type {1}. */, type3, type)); + } + retArgs[i] = VariantFactory.Convert(obj, type3); + } + if (!_methodHeader.IsStatic() && GetTypeById(_methodHeader.ClassId).IsValueType) + { + var expr_EB = new VariantBaseHolder(); + expr_EB.SetValue(retArgs[0]); + retArgs[0] = expr_EB; + } + for (var j = 0; j < num; j++) + { + if (methodHeaderArgsTypeToOutput[j].IsOutput) + { + var expr_116 = new VariantBaseHolder(); + expr_116.SetValue(retArgs[j]); + retArgs[j] = expr_116; + } + } + return retArgs; + } + + // Token: 0x0600025D RID: 605 RVA: 0x00010B3C File Offset: 0x0000ED3C + private void Stind() // \u0003 + { + var v2 = PopVariant(); + var v1 = PopVariant(); + AssignByReference(v1, v2); + } + + // Token: 0x0600025E RID: 606 RVA: 0x00010B60 File Offset: 0x0000ED60 + private void Endfinally_(VariantBase dummy) // \u0005\u2000\u2001 + { + ExecuteExceptionHandler(); + } + + // Token: 0x0600025F RID: 607 RVA: 0x00010B68 File Offset: 0x0000ED68 + private bool PosInRange(long pos, uint start, uint len) // \u0002 + { + return pos >= (long)(ulong)start && pos <= (long)(ulong)(start + len); + } + + // Token: 0x06000260 RID: 608 RVA: 0x00010B7C File Offset: 0x0000ED7C + private bool IsCompatible(MethodBase mb) // \u0002 + { + return mb.IsVirtual && GetTypeById(_methodHeader.ClassId).IsSubclassOf(mb.DeclaringType); + } + + // Token: 0x06000263 RID: 611 RVA: 0x00010C00 File Offset: 0x0000EE00 + private void Stelem_(VariantBase vTypeId) // \u0006\u2004\u2000 + { + Stelem(GetTypeById(((IntVariant)vTypeId).GetValue())); + } + + // Token: 0x06000265 RID: 613 RVA: 0x00010C40 File Offset: 0x0000EE40 + private void Ldelem_u1_(VariantBase dummy) // \u0006\u2004 + { + Ldelem(typeof(byte)); + } + + // Token: 0x06000267 RID: 615 RVA: 0x00010C80 File Offset: 0x0000EE80 + private void Cgt_(VariantBase dummy) // \u0005\u2001\u2000 + { + var v2 = PopVariant(); + var v1 = PopVariant(); + var push = new IntVariant(); + push.SetValue(UniCompare(v1, v2, ComparisonKind.GT, false) ? 1 : 0); + PushVariant(push); + } + + private VariantBase And(VariantBase org_v1, VariantBase org_v2) + { + VariantBase v1, v2; + var tc = CommonType(org_v1, org_v2, out v1, out v2, true); + VariantBase ret; + switch (tc) + { + case VariantBase.Vtc.Tc9Uint: + uint uv1 = ((UintVariant)v1).GetValue(), uv2 = ((UintVariant)v2).GetValue(); + var uvret = new UintVariant(); + ret = uvret; + uvret.SetValue(uv1 & uv2); + break; + case VariantBase.Vtc.Tc19Int: + int iv1 = ((IntVariant)v1).GetValue(), iv2 = ((IntVariant)v2).GetValue(); + var ivret = new IntVariant(); + ret = ivret; + ivret.SetValue(iv1 & iv2); + break; + case VariantBase.Vtc.Tc21Double: + { + /*double dv1 = ((DoubleVariant)v1).GetValue(), dv2 = ((DoubleVariant)v2).GetValue(); // естественный алгоритм + long lv1 = (dv1 < 0) ? (long)dv1 : (long)(ulong)dv1; + long lv2 = (dv2 < 0) ? (long)dv2 : (long)(ulong)dv2; + var dvret = new DoubleVariant(); + ret = dvret; + var l64 = (ulong) lv1 & (ulong) lv2; + if (l64 >> 32 == UInt32.MaxValue) l64 &= UInt32.MaxValue; + dvret.SetValue(l64);*/ + var dvret = new DoubleVariant(); + ret = dvret; + dvret.SetValue((4 == IntPtr.Size) ? Double.NaN : (double)0); // иногда у фреймворка бывает мусор, но чаще эти значения... + } + break; + case VariantBase.Vtc.Tc8Float: + { + /*float fv1 = ((FloatVariant) v1).GetValue(), fv2 = ((FloatVariant) v2).GetValue(); // естественный алгоритм + long lv1 = (fv1 < 0) ? (long)fv1 : (long)(ulong)fv1; + long lv2 = (fv2 < 0) ? (long)fv2 : (long)(ulong)fv2; + var fvret = new FloatVariant(); + ret = fvret; + var l64 = (ulong)lv1 & (ulong)lv2; + if (l64 >> 32 == UInt32.MaxValue) l64 &= UInt32.MaxValue; + fvret.SetValue(l64);*/ + var fvret = new FloatVariant(); + ret = fvret; + fvret.SetValue((4 == IntPtr.Size) ? float.NaN : (float)0.0); // иногда у фреймворка бывает мусор, но чаще эти значения... + } + break; + case VariantBase.Vtc.Tc24Long: + { + long lv1 = ((LongVariant)v1).GetValue(), lv2 = ((LongVariant)v2).GetValue(); + var lvret = new LongVariant(); + ret = lvret; + lvret.SetValue(lv1 & lv2); + } + break; + case VariantBase.Vtc.Tc7Ulong: + ulong ulv1 = ((UlongVariant)v1).GetValue(), ulv2 = ((UlongVariant)v2).GetValue(); + var ulvret = new UlongVariant(); + ret = ulvret; + ulvret.SetValue(ulv1 & ulv2); + break; + default: + // это нужно будет заменить на соотв. msil-код + var dyn = new DynamicMethod(String.Empty, typeof(IntPtr), new[] { typeof(object), typeof(object) }, typeof(void), true); + var gen = dyn.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_1); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(OpCodes.And); + gen.Emit(OpCodes.Ret); + ret = new IntPtrVariant(); + ((IntPtrVariant)ret).SetValue(((IntPtr)dyn.Invoke(null, new[] { org_v1.GetValueAbstract(), org_v2.GetValueAbstract() }))); + break; + } + return ret; + } + + // Token: 0x0600026E RID: 622 RVA: 0x000110D8 File Offset: 0x0000F2D8 + private void Ldind(Type t) // \u0005 + { + PushVariant(VariantFactory.Convert(FetchByAddr(PopVariant()).GetValueAbstract(), t)); + } + + // Token: 0x0600026F RID: 623 RVA: 0x00011104 File Offset: 0x0000F304 + private void Starg_(VariantBase vidx) // \u000F\u2008\u2000 + { + var idx = (UshortVariant)vidx; + _variantOutputArgs[idx.GetValue()].CopyFrom(PopVariant()); + } + + // Token: 0x06000270 RID: 624 RVA: 0x00011138 File Offset: 0x0000F338 + private void Ret() // \u0008 + { + _retFound = true; + } + + // Token: 0x06000273 RID: 627 RVA: 0x00011480 File Offset: 0x0000F680 + private void Stind_r8_(VariantBase dummy) // \u0005\u2004\u2000 + { + Stind(); + } + + // Token: 0x06000275 RID: 629 RVA: 0x00011510 File Offset: 0x0000F710 + private void Rethrow_(VariantBase dummy) // \u0003\u200A\u2000 + { + if (_exception == null) + { + throw new InvalidOperationException(); + } + _myBufferPos = _myBufferReader.GetBuffer().GetPos(); + ThrowStoreCrossDomain(_exception); + } + + // Token: 0x06000278 RID: 632 RVA: 0x00011838 File Offset: 0x0000FA38 + private void Ldelem_u4_(VariantBase dummy) // \u0003\u2003 + { + Ldelem(typeof(uint)); + } + + // Token: 0x0600027A RID: 634 RVA: 0x00011994 File Offset: 0x0000FB94 + private void Invoke(VmMethodRefTokenInfo mref) // \u0002 + { + //var arg_18_0 = (U0008U2007)U0003U2008.Get_u0005(); + var methodBase = FindMethodById(mref.Pos, ReadToken(mref.Pos)); + //methodBase.GetParameters(); + var pos = mref.Flags; + var mayVirtual = (pos & 1073741824) != 0; + pos &= -1073741825; + var methodGenericArgs = _methodGenericArgs; + var classGenericArgs = _classGenericArgs; + try + { + _methodGenericArgs = methodBase is ConstructorInfo ? Type.EmptyTypes : methodBase.GetGenericArguments(); + _classGenericArgs = methodBase.DeclaringType.GetGenericArguments(); + Invoke(pos, _methodGenericArgs, _classGenericArgs, mayVirtual); + } + finally + { + _methodGenericArgs = methodGenericArgs; + _classGenericArgs = classGenericArgs; + } + } + + // Token: 0x0600027B RID: 635 RVA: 0x00011A5C File Offset: 0x0000FC5C + private void Ldc_i8_(VariantBase val) // \u0006\u2007\u2000 + { + PushVariant(val); + } + + // Token: 0x0600027E RID: 638 RVA: 0x00011CB8 File Offset: 0x0000FEB8 + private void Ldelem_r8_(VariantBase dummy) // \u000E\u2002\u2000 + { + Ldelem(typeof(double)); + } + + // Token: 0x06000280 RID: 640 RVA: 0x00011DB4 File Offset: 0x0000FFB4 + private void Stloc_3_(VariantBase dummy) // \u0003\u2004\u2000 + { + PopToLocal(3); + } + + // Token: 0x06000281 RID: 641 RVA: 0x00011DC0 File Offset: 0x0000FFC0 + private void Ckfinite_(VariantBase dummy) // \u000F\u2003 + { + var v = PopVariant(); + if (v.GetTypeCode() == VariantBase.Vtc.Tc5Enum) + { + v = VariantBase.SignedVariantFromEnum((EnumVariant)v); + } + double val = double.NaN; + bool con = v.GetValueAbstract() is IConvertible; + if (con) + { + val = Convert.ToDouble(v.GetValueAbstract()); + if (double.IsNaN(val) || double.IsInfinity(val)) + { + throw new OverflowException(StringDecryptor.GetString(-1550347095) /* The value is not finite real number. */); + } + } + if (IsFloating(v)) + { + PushVariant(v); + } else + { + var push = new DoubleVariant(); + push.SetValue(val); + PushVariant(push); + } + } + + // Token: 0x06000288 RID: 648 RVA: 0x00012170 File Offset: 0x00010370 + private void Stind_ref_(VariantBase dummy) // \u0002\u2008 + { + Stind(); + } + + // Token: 0x06000289 RID: 649 RVA: 0x00012178 File Offset: 0x00010378 + private void PopToLocal(int idx) // \u0002 + { + var pop = PopVariant(); + if (pop is ReferenceVariantBase) + { + _localVariables[idx] = pop; + return; + } + _localVariables[idx].CopyFrom(pop); + } + + // Token: 0x0600028B RID: 651 RVA: 0x00012260 File Offset: 0x00010460 + private void Ldobj_(VariantBase vTypeId) // \u000E\u2008 + { + var type = GetTypeById(((IntVariant)vTypeId).GetValue()); + Ldind(type); + } + + // Token: 0x0600028C RID: 652 RVA: 0x00012288 File Offset: 0x00010488 + private void Ldloc_1_(VariantBase dummy) // \u0003\u2008\u2000 + { + PushVariant(_localVariables[1].Clone()); + } + + // Token: 0x0600028E RID: 654 RVA: 0x00012348 File Offset: 0x00010548 + private void Ldelem_i1_(VariantBase dummy) // \u0005\u2009\u2000 + { + Ldelem(typeof(sbyte)); + } + + // Token: 0x06000290 RID: 656 RVA: 0x00012370 File Offset: 0x00010570 + private void JumpToPos(uint val) // \u0002 + { + _storedPos = val; + } + + // Token: 0x06000291 RID: 657 RVA: 0x00012380 File Offset: 0x00010580 + public void VoidInvoke(Stream virtualizedStream, string pos, object[] args) // \u0002 + { + Invoke(virtualizedStream, pos, args); + } + + // Token: 0x06000295 RID: 661 RVA: 0x00012420 File Offset: 0x00010620 + private void _u0002u2002u2001(VariantBase dummy) // \u0002\u2002\u2001 + { + } + + // Token: 0x06000298 RID: 664 RVA: 0x00012590 File Offset: 0x00010790 + private void LoopUntilRet() // \u0005\u2000 + { + var usedSize = _myBufferReader.GetBuffer().UsedSize(); + while (!_retFound) + { + if (_storedPos.HasValue) + { + _myBufferReader.GetBuffer().SetPos((long)(ulong)_storedPos.Value); + _storedPos = null; + } + ExecuteNextInstruction(); + if (_myBufferReader.GetBuffer().GetPos() >= usedSize && !_storedPos.HasValue) + { + break; + } + } + } + + // Token: 0x06000299 RID: 665 RVA: 0x00012614 File Offset: 0x00010814 + private VmInstrInfo GetInstrById(int id) // \u0002 + { + return _instrCodesDb.MyFieldsEnumerator().FirstOrDefault(current => current.Id == id); + } + + // Token: 0x0600029A RID: 666 RVA: 0x00012670 File Offset: 0x00010870 + private void Ldloc_(VariantBase val) // \u000F\u200A\u2000 + { + PushVariant(_localVariables[((UshortVariant)val).GetValue()].Clone()); + } + + // Token: 0x0600029E RID: 670 RVA: 0x00012718 File Offset: 0x00010918 + private bool Isinst(VariantBase obj, Type t) // \u0002 + { + if (obj.GetValueAbstract() == null) + { + return true; + } + var type = obj.GetVariantType() ?? obj.GetValueAbstract().GetType(); + if (type == t || t.IsAssignableFrom(type)) + { + return true; + } + if (!type.IsValueType && !t.IsValueType && Marshal.IsComObject(obj.GetValueAbstract())) + { + IntPtr intPtr; + try + { + intPtr = Marshal.GetComInterfaceForObject(obj.GetValueAbstract(), t); + } + catch (InvalidCastException) + { + intPtr = IntPtr.Zero; + } + if (intPtr != IntPtr.Zero) + { + try + { + Marshal.Release(intPtr); + } + catch + { + } + return true; + } + } + return false; + } + + // Token: 0x0600029F RID: 671 RVA: 0x000127C4 File Offset: 0x000109C4 + private void Ldind_r8_(VariantBase dummy) // \u000E\u2008\u2000 + { + Ldind(typeof(double)); + } + + // Token: 0x060002A1 RID: 673 RVA: 0x00012870 File Offset: 0x00010A70 + private void Stobj_(VariantBase dummy) // \u0005\u2009 + { + Stind(); + } + + // Token: 0x060002A4 RID: 676 RVA: 0x00012A44 File Offset: 0x00010C44 + private void Cgt_un_(VariantBase dummy) // \u0006\u2002 + { + var v2 = PopVariant(); + var v1 = PopVariant(); + var push = new IntVariant(); + push.SetValue(UniCompare(v1, v2, ComparisonKind.GT, true) ? 1 : 0); + PushVariant(push); + } + + // Token: 0x060002A7 RID: 679 RVA: 0x00012CDC File Offset: 0x00010EDC + private bool AreCompatible(Type t1, UniversalTokenInfo ut2) // \u0002 + { + var t2 = (VmClassTokenInfo)ut2.VmToken; + if (ElementedTypeHelper.TryGoToElementType(t1).IsGenericParameter) + { + return t2 == null || t2.IsOuterClassGeneric; + } + return TypeCompatibility.Check(t1, GetTypeById(ut2.MetadataToken)); + } + + // Token: 0x060002A9 RID: 681 RVA: 0x00012D38 File Offset: 0x00010F38 + private void Ldloca_(VariantBase vLocIdx) // \u0006\u2005 + { + var push = new LocalsIdxHolderVariant(); + push.SetValue(((UshortVariant)vLocIdx).GetValue()); + PushVariant(push); + } + + // Token: 0x060002AA RID: 682 RVA: 0x00012D64 File Offset: 0x00010F64 + private void Ldarg_3_(VariantBase dummy) // \u000E\u2009 + { + PushVariant(_variantOutputArgs[3].Clone()); + } + + // Token: 0x060002AC RID: 684 RVA: 0x00012DB8 File Offset: 0x00010FB8 + /*[Conditional("DEBUG")] + public static void DoNothing(string dummy) // \u0002 + { + }*/ + + // Token: 0x0600021F RID: 543 RVA: 0x0000C8BC File Offset: 0x0000AABC + private Dictionary<int, VmInstr> CreateVmInstrDb() // \u0002 + { + return new Dictionary<int, VmInstr>(256) + { + { + _instrCodesDb.Conv_ovf_i4_un_.Id, + new VmInstr(_instrCodesDb.Conv_ovf_i4_un_, Conv_ovf_i4_un_) + }, + { + _instrCodesDb.Shr_un_.Id, + new VmInstr(_instrCodesDb.Shr_un_, Shr_un_) + }, + { + _instrCodesDb.Conv_i_.Id, + new VmInstr(_instrCodesDb.Conv_i_, Conv_i_) + }, + { + _instrCodesDb.Conv_ovf_i_un_.Id, + new VmInstr(_instrCodesDb.Conv_ovf_i_un_, Conv_ovf_i_un_) + }, + { + _instrCodesDb.Stelem_i_.Id, + new VmInstr(_instrCodesDb.Stelem_i_, Stelem_i_) + }, + { + _instrCodesDb.Starg_s_.Id, + new VmInstr(_instrCodesDb.Starg_s_, Starg_s_) + }, + { + _instrCodesDb.Sizeof_.Id, + new VmInstr(_instrCodesDb.Sizeof_, Sizeof_) + }, + { + _instrCodesDb.Ldarg_s_.Id, + new VmInstr(_instrCodesDb.Ldarg_s_, Ldarg_s_) + }, + { + _instrCodesDb.Stelem_i4_.Id, + new VmInstr(_instrCodesDb.Stelem_i4_, Stelem_i4_) + }, + { + _instrCodesDb.Calli_.Id, + new VmInstr(_instrCodesDb.Calli_, Calli_) + }, + { + _instrCodesDb.Ldc_i4_7_.Id, + new VmInstr(_instrCodesDb.Ldc_i4_7_, Ldc_i4_7_) + }, + { + _instrCodesDb.Newobj_.Id, + new VmInstr(_instrCodesDb.Newobj_, Newobj_) + }, + { + _instrCodesDb.Ldind_u4_.Id, + new VmInstr(_instrCodesDb.Ldind_u4_, Ldind_u4_) + }, + { + _instrCodesDb.Cgt_un_.Id, + new VmInstr(_instrCodesDb.Cgt_un_, Cgt_un_) + }, + { + _instrCodesDb.Conv_u1_.Id, + new VmInstr(_instrCodesDb.Conv_u1_, Conv_u1_) + }, + { + _instrCodesDb.Ldelem_ref_.Id, + new VmInstr(_instrCodesDb.Ldelem_ref_, Ldelem_ref_) + }, + { + _instrCodesDb.U0006U2008U2000.Id, + new VmInstr(_instrCodesDb.U0006U2008U2000, _u0002u2002u2001) + }, + { + _instrCodesDb.Newarr_.Id, + new VmInstr(_instrCodesDb.Newarr_, Newarr_) + }, + { + _instrCodesDb.Ldarga_s_.Id, + new VmInstr(_instrCodesDb.Ldarga_s_, Ldarga_s_) + }, + { + _instrCodesDb.Bgt_.Id, + new VmInstr(_instrCodesDb.Bgt_, Bgt_) + }, + { + _instrCodesDb.Ldflda_.Id, + new VmInstr(_instrCodesDb.Ldflda_, Ldflda_) + }, + { + _instrCodesDb.Sub_.Id, + new VmInstr(_instrCodesDb.Sub_, Sub_) + }, + { + _instrCodesDb.Endfilter_.Id, + new VmInstr(_instrCodesDb.Endfilter_, Endfilter_) + }, + { + _instrCodesDb.Conv_ovf_u_un_.Id, + new VmInstr(_instrCodesDb.Conv_ovf_u_un_, Conv_ovf_u_un_) + }, + { + _instrCodesDb.Ldc_i4_1_.Id, + new VmInstr(_instrCodesDb.Ldc_i4_1_, Ldc_i4_1_) + }, + { + _instrCodesDb.Conv_ovf_i_.Id, + new VmInstr(_instrCodesDb.Conv_ovf_i_, Conv_ovf_i_) + }, + { + _instrCodesDb.Add_ovf_.Id, + new VmInstr(_instrCodesDb.Add_ovf_, Add_ovf_) + }, + { + _instrCodesDb.Ldftn_.Id, + new VmInstr(_instrCodesDb.Ldftn_, Ldftn_) + }, + { + _instrCodesDb.Stfld_.Id, + new VmInstr(_instrCodesDb.Stfld_, Stfld_) + }, + { + _instrCodesDb.Ldc_i4_5_.Id, + new VmInstr(_instrCodesDb.Ldc_i4_5_, Ldc_i4_5_) + }, + { + _instrCodesDb.Xor_.Id, + new VmInstr(_instrCodesDb.Xor_, Xor_) + }, + { + _instrCodesDb.Conv_u2_.Id, + new VmInstr(_instrCodesDb.Conv_u2_, Conv_u2_) + }, + { + _instrCodesDb.Div_un_.Id, + new VmInstr(_instrCodesDb.Div_un_, Div_un_) + }, + { + _instrCodesDb.Stloc_3_.Id, + new VmInstr(_instrCodesDb.Stloc_3_, Stloc_3_) + }, + { + _instrCodesDb.Ret_.Id, + new VmInstr(_instrCodesDb.Ret_, Ret_) + }, + { + _instrCodesDb.Ldc_i4_m1_.Id, + new VmInstr(_instrCodesDb.Ldc_i4_m1_, Ldc_i4_m1_) + }, + { + _instrCodesDb.Ldarg_1_.Id, + new VmInstr(_instrCodesDb.Ldarg_1_, Ldarg_1_) + }, + { + _instrCodesDb.Div_.Id, + new VmInstr(_instrCodesDb.Div_, Div_) + }, + { + _instrCodesDb.Ldnull_.Id, + new VmInstr(_instrCodesDb.Ldnull_, Ldnull_) + }, + { + _instrCodesDb.Break_.Id, + new VmInstr(_instrCodesDb.Break_, Break_) + }, + { + _instrCodesDb.Cgt_.Id, + new VmInstr(_instrCodesDb.Cgt_, Cgt_) + }, + { + _instrCodesDb.Arglist_.Id, + new VmInstr(_instrCodesDb.Arglist_, Arglist_) + }, + { + _instrCodesDb.Ldloc_.Id, + new VmInstr(_instrCodesDb.Ldloc_, Ldloc_) + }, + { + _instrCodesDb.Conv_u_.Id, + new VmInstr(_instrCodesDb.Conv_u_, Conv_u_) + }, + { + _instrCodesDb.Ldelem_i_.Id, + new VmInstr(_instrCodesDb.Ldelem_i_, Ldelem_i_) + }, + { + _instrCodesDb.Conv_ovf_i1_un_.Id, + new VmInstr(_instrCodesDb.Conv_ovf_i1_un_, Conv_ovf_i1_un_) + }, + { + _instrCodesDb.Cpblk_.Id, + new VmInstr(_instrCodesDb.Cpblk_, Cpblk_) + }, + { + _instrCodesDb.Add_.Id, + new VmInstr(_instrCodesDb.Add_, Add_) + }, + { + _instrCodesDb.Initblk_.Id, + new VmInstr(_instrCodesDb.Initblk_, Initblk_) + }, + { + _instrCodesDb.Ldind_i_.Id, + new VmInstr(_instrCodesDb.Ldind_i_, Ldind_i_) + }, + { + _instrCodesDb.Ldelem_u4_.Id, + new VmInstr(_instrCodesDb.Ldelem_u4_, Ldelem_u4_) + }, + { + _instrCodesDb.Stind_ref_.Id, + new VmInstr(_instrCodesDb.Stind_ref_, Stind_ref_) + }, + { + _instrCodesDb.Ldelem_i1_.Id, + new VmInstr(_instrCodesDb.Ldelem_i1_, Ldelem_i1_) + }, + { + _instrCodesDb.Ldloc_3_.Id, + new VmInstr(_instrCodesDb.Ldloc_3_, Ldloc_3_) + }, + { + _instrCodesDb.Stind_i8_.Id, + new VmInstr(_instrCodesDb.Stind_i8_, Stind_i8_) + }, + { + _instrCodesDb.Conv_i1_.Id, + new VmInstr(_instrCodesDb.Conv_i1_, Conv_i1_) + }, + { + _instrCodesDb.Ldelem_.Id, + new VmInstr(_instrCodesDb.Ldelem_, Ldelem_) + }, + { + _instrCodesDb.Clt_un_.Id, + new VmInstr(_instrCodesDb.Clt_un_, Clt_un_) + }, + { + _instrCodesDb.Ldelem_i4_.Id, + new VmInstr(_instrCodesDb.Ldelem_i4_, Ldelem_i4_) + }, + { + _instrCodesDb.Mkrefany_.Id, + new VmInstr(_instrCodesDb.Mkrefany_, Mkrefany_) + }, + { + _instrCodesDb.Neg_.Id, + new VmInstr(_instrCodesDb.Neg_, Neg_) + }, + { + _instrCodesDb.Leave_.Id, + new VmInstr(_instrCodesDb.Leave_, Leave_) + }, + { + _instrCodesDb.Ldc_i4_2_.Id, + new VmInstr(_instrCodesDb.Ldc_i4_2_, Ldc_i4_2_) + }, + { + _instrCodesDb.Conv_ovf_i2_.Id, + new VmInstr(_instrCodesDb.Conv_ovf_i2_, Conv_ovf_i2_) + }, + { + _instrCodesDb.Ldloc_2_.Id, + new VmInstr(_instrCodesDb.Ldloc_2_, Ldloc_2_) + }, + { + _instrCodesDb.Bgt_un_.Id, + new VmInstr(_instrCodesDb.Bgt_un_, Bgt_un_) + }, + { + _instrCodesDb.Stsfld_.Id, + new VmInstr(_instrCodesDb.Stsfld_, Stsfld_) + }, + /*{ + _instrCodesDb.Nop_.Id, + new VmInstr(_instrCodesDb.Nop_, u000Fu2004) + },*/ + { + _instrCodesDb.Shr_.Id, + new VmInstr(_instrCodesDb.Shr_, Shr_) + }, + { + _instrCodesDb.Ldind_ref_.Id, + new VmInstr(_instrCodesDb.Ldind_ref_, Ldind_ref_) + }, + { + _instrCodesDb.Ldfld_.Id, + new VmInstr(_instrCodesDb.Ldfld_, Ldfld_) + }, + { + _instrCodesDb.Ldlen_.Id, + new VmInstr(_instrCodesDb.Ldlen_, Ldlen_) + }, + { + _instrCodesDb.Stelem_ref_.Id, + new VmInstr(_instrCodesDb.Stelem_ref_, Stelem_ref_) + }, + { + _instrCodesDb.Ceq_.Id, + new VmInstr(_instrCodesDb.Ceq_, Ceq_) + }, + { + _instrCodesDb.Conv_ovf_u2_.Id, + new VmInstr(_instrCodesDb.Conv_ovf_u2_, Conv_ovf_u2_) + }, + { + _instrCodesDb.Add_ovf_un_.Id, + new VmInstr(_instrCodesDb.Add_ovf_un_, Add_ovf_un_) + }, + { + _instrCodesDb.Conv_ovf_i8_.Id, + new VmInstr(_instrCodesDb.Conv_ovf_i8_, Conv_ovf_i8_) + }, + { + _instrCodesDb.Stind_i2_.Id, + new VmInstr(_instrCodesDb.Stind_i2_, Stind_i2_) + }, + { + _instrCodesDb.Stelem_i1_.Id, + new VmInstr(_instrCodesDb.Stelem_i1_, Stelem_i1_) + }, + { + _instrCodesDb.Ldloca_.Id, + new VmInstr(_instrCodesDb.Ldloca_, Ldloca_) + }, + { + _instrCodesDb.Stind_r4_.Id, + new VmInstr(_instrCodesDb.Stind_r4_, Stind_r4_) + }, + { + _instrCodesDb.Stloc_s_.Id, + new VmInstr(_instrCodesDb.Stloc_s_, Stloc_s_) + }, + { + _instrCodesDb.Refanyval_.Id, + new VmInstr(_instrCodesDb.Refanyval_, Refanyval_) + }, + { + _instrCodesDb.Clt_.Id, + new VmInstr(_instrCodesDb.Clt_, Clt_) + }, + { + _instrCodesDb.Stelem_r4_.Id, + new VmInstr(_instrCodesDb.Stelem_r4_, Stelem_r4_) + }, + { + _instrCodesDb.Stelem_r8_.Id, + new VmInstr(_instrCodesDb.Stelem_r8_, Stelem_r8_) + }, + { + _instrCodesDb.Conv_u4_.Id, + new VmInstr(_instrCodesDb.Conv_u4_, Conv_u4_) + }, + { + _instrCodesDb.Ldc_i8_.Id, + new VmInstr(_instrCodesDb.Ldc_i8_, Ldc_i8_) + }, + { + _instrCodesDb.Ldind_r4_.Id, + new VmInstr(_instrCodesDb.Ldind_r4_, Ldind_r4_) + }, + { + _instrCodesDb.Conv_r_un_.Id, + new VmInstr(_instrCodesDb.Conv_r_un_, Conv_r_un_) + }, + { + _instrCodesDb.Ldtoken_.Id, + new VmInstr(_instrCodesDb.Ldtoken_, Ldtoken_) + }, + { + _instrCodesDb.Blt_un_.Id, + new VmInstr(_instrCodesDb.Blt_un_, Blt_un_) + }, + { + _instrCodesDb.Brtrue_.Id, + new VmInstr(_instrCodesDb.Brtrue_, Brtrue_) + }, + { + _instrCodesDb.Switch_.Id, + new VmInstr(_instrCodesDb.Switch_, Switch_) + }, + { + _instrCodesDb.Refanytype_.Id, + new VmInstr(_instrCodesDb.Refanytype_, Refanytype_) + }, + { + _instrCodesDb.Stobj_.Id, + new VmInstr(_instrCodesDb.Stobj_, Stobj_) + }, + { + _instrCodesDb.Ble_un_.Id, + new VmInstr(_instrCodesDb.Ble_un_, Ble_un_) + }, + { + _instrCodesDb.Conv_ovf_i8_un_.Id, + new VmInstr(_instrCodesDb.Conv_ovf_i8_un_, Conv_ovf_i8_un_) + }, + { + _instrCodesDb.Conv_ovf_u4_un_.Id, + new VmInstr(_instrCodesDb.Conv_ovf_u4_un_, Conv_ovf_u4_un_) + }, + { + _instrCodesDb.Ldind_i8_.Id, + new VmInstr(_instrCodesDb.Ldind_i8_, Ldind_i8_) + }, + { + _instrCodesDb.U000EU2006U2000.Id, + new VmInstr(_instrCodesDb.U000EU2006U2000, Invoke) + }, + { + _instrCodesDb.Endfinally_.Id, + new VmInstr(_instrCodesDb.Endfinally_, Endfinally_) + }, + { + _instrCodesDb.Conv_ovf_u8_un_.Id, + new VmInstr(_instrCodesDb.Conv_ovf_u8_un_, Conv_ovf_u8_un_) + }, + { + _instrCodesDb.Ldelem_i2_.Id, + new VmInstr(_instrCodesDb.Ldelem_i2_, Ldelem_i2_) + }, + { + _instrCodesDb.Ldc_i4_.Id, + new VmInstr(_instrCodesDb.Ldc_i4_, Ldc_i4_) + }, + { + _instrCodesDb.U000FU2001.Id, + new VmInstr(_instrCodesDb.U000FU2001, _u0006u2003u2001) + }, + { + _instrCodesDb.Conv_i4_.Id, + new VmInstr(_instrCodesDb.Conv_i4_, Conv_i4_) + }, + { + _instrCodesDb.Ldind_u1_.Id, + new VmInstr(_instrCodesDb.Ldind_u1_, Ldind_u1_) + }, + { + _instrCodesDb.Rethrow_.Id, + new VmInstr(_instrCodesDb.Rethrow_, Rethrow_) + }, + { + _instrCodesDb.Conv_ovf_i1_.Id, + new VmInstr(_instrCodesDb.Conv_ovf_i1_, Conv_ovf_i1_) + }, + { + _instrCodesDb.Box_.Id, + new VmInstr(_instrCodesDb.Box_, Box_) + }, + { + _instrCodesDb.Localloc_.Id, + new VmInstr(_instrCodesDb.Localloc_, Localloc_) + }, + { + _instrCodesDb.Ldelem_r8_.Id, + new VmInstr(_instrCodesDb.Ldelem_r8_, Ldelem_r8_) + }, + { + _instrCodesDb.Throw_.Id, + new VmInstr(_instrCodesDb.Throw_, Throw_) + }, + { + _instrCodesDb.Ldvirtftn_.Id, + new VmInstr(_instrCodesDb.Ldvirtftn_, Ldvirtftn_) + }, + { + _instrCodesDb.Mul_ovf_un_.Id, + new VmInstr(_instrCodesDb.Mul_ovf_un_, Mul_ovf_un_) + }, + { + _instrCodesDb.Conv_ovf_i4_.Id, + new VmInstr(_instrCodesDb.Conv_ovf_i4_, Conv_ovf_i4_) + }, + { + _instrCodesDb.Ldloc_0_.Id, + new VmInstr(_instrCodesDb.Ldloc_0_, Ldloc_0_) + }, + { + _instrCodesDb.Starg_.Id, + new VmInstr(_instrCodesDb.Starg_, Starg_) + }, + { + _instrCodesDb.Stind_i1_.Id, + new VmInstr(_instrCodesDb.Stind_i1_, Stind_i1_) + }, + { + _instrCodesDb.Ldind_i2_.Id, + new VmInstr(_instrCodesDb.Ldind_i2_, Ldind_i2_) + }, + { + _instrCodesDb.And_.Id, + new VmInstr(_instrCodesDb.And_, And_) + }, + { + _instrCodesDb.Ldc_i4_6_.Id, + new VmInstr(_instrCodesDb.Ldc_i4_6_, Ldc_i4_6_) + }, + { + _instrCodesDb.Nop_.Id, + new VmInstr(_instrCodesDb.Nop_, Nop_) + }, + { + _instrCodesDb.Ldind_i4_.Id, + new VmInstr(_instrCodesDb.Ldind_i4_, Ldind_i4_) + }, + { + _instrCodesDb.Dup_.Id, + new VmInstr(_instrCodesDb.Dup_, Dup_) + }, + { + _instrCodesDb.Mul_.Id, + new VmInstr(_instrCodesDb.Mul_, Mul_) + }, + { + _instrCodesDb.Stloc_2_.Id, + new VmInstr(_instrCodesDb.Stloc_2_, Stloc_2_) + }, + { + _instrCodesDb.Or_.Id, + new VmInstr(_instrCodesDb.Or_, Or_) + }, + { + _instrCodesDb.Conv_u8_.Id, + new VmInstr(_instrCodesDb.Conv_u8_, Conv_u8_) + }, + { + _instrCodesDb.Conv_ovf_u1_.Id, + new VmInstr(_instrCodesDb.Conv_ovf_u1_, Conv_ovf_u1_) + }, + { + _instrCodesDb.Sub_ovf_.Id, + new VmInstr(_instrCodesDb.Sub_ovf_, Sub_ovf_) + }, + { + _instrCodesDb.Conv_ovf_u1_un_.Id, + new VmInstr(_instrCodesDb.Conv_ovf_u1_un_, Conv_ovf_u1_un_) + }, + { + _instrCodesDb.Ldelem_r4_.Id, + new VmInstr(_instrCodesDb.Ldelem_r4_, Ldelem_r4_) + }, + { + _instrCodesDb.Conv_r8_.Id, + new VmInstr(_instrCodesDb.Conv_r8_, Conv_r8_) + }, + { + _instrCodesDb.Stloc_0_.Id, + new VmInstr(_instrCodesDb.Stloc_0_, Stloc_0_) + }, + { + _instrCodesDb.Conv_ovf_u8_.Id, + new VmInstr(_instrCodesDb.Conv_ovf_u8_, Conv_ovf_u8_) + }, + { + _instrCodesDb.Brfalse_.Id, + new VmInstr(_instrCodesDb.Brfalse_, Brfalse_) + }, + { + _instrCodesDb.Ldarg_3_.Id, + new VmInstr(_instrCodesDb.Ldarg_3_, Ldarg_3_) + }, + { + _instrCodesDb.Ldarg_.Id, + new VmInstr(_instrCodesDb.Ldarg_, Ldarg_) + }, + { + _instrCodesDb.Ldc_r4_.Id, + new VmInstr(_instrCodesDb.Ldc_r4_, Ldc_r4_) + }, + { + _instrCodesDb.Initobj_.Id, + new VmInstr(_instrCodesDb.Initobj_, Initobj_) + }, + { + _instrCodesDb.Stloc_.Id, + new VmInstr(_instrCodesDb.Stloc_, Stloc_) + }, + { + _instrCodesDb.Stind_i4_.Id, + new VmInstr(_instrCodesDb.Stind_i4_, Stind_i4_) + }, + { + _instrCodesDb.Callvirt_.Id, + new VmInstr(_instrCodesDb.Callvirt_, Callvirt_) + }, + { + _instrCodesDb.Stelem_i2_.Id, + new VmInstr(_instrCodesDb.Stelem_i2_, Stelem_i2_) + }, + { + _instrCodesDb.Conv_ovf_u_.Id, + new VmInstr(_instrCodesDb.Conv_ovf_u_, Conv_ovf_u_) + }, + { + _instrCodesDb.Cpobj_.Id, + new VmInstr(_instrCodesDb.Cpobj_, Cpobj_) + }, + { + _instrCodesDb.Rem_.Id, + new VmInstr(_instrCodesDb.Rem_, Rem_) + }, + { + _instrCodesDb.Stind_r8_.Id, + new VmInstr(_instrCodesDb.Stind_r8_, Stind_r8_) + }, + { + _instrCodesDb.Stloc_1_.Id, + new VmInstr(_instrCodesDb.Stloc_1_, Stloc_1_) + }, + { + _instrCodesDb.Conv_ovf_u4_.Id, + new VmInstr(_instrCodesDb.Conv_ovf_u4_, Conv_ovf_u4_) + }, + { + _instrCodesDb.Ldc_i4_0_.Id, + new VmInstr(_instrCodesDb.Ldc_i4_0_, Ldc_i4_0_) + }, + { + _instrCodesDb.Stind_i_.Id, + new VmInstr(_instrCodesDb.Stind_i_, Stind_i_) + }, + { + _instrCodesDb.Stelem_i8_.Id, + new VmInstr(_instrCodesDb.Stelem_i8_, Stelem_i8_) + }, + { + _instrCodesDb.Ldelema_.Id, + new VmInstr(_instrCodesDb.Ldelema_, Ldelema_) + }, + { + _instrCodesDb.Ldsflda_.Id, + new VmInstr(_instrCodesDb.Ldsflda_, Ldsflda_) + }, + { + _instrCodesDb.Ldsfld_.Id, + new VmInstr(_instrCodesDb.Ldsfld_, Ldsfld_) + }, + { + _instrCodesDb.Isinst_.Id, + new VmInstr(_instrCodesDb.Isinst_, Isinst_) + }, + { + _instrCodesDb.Conv_i2_.Id, + new VmInstr(_instrCodesDb.Conv_i2_, Conv_i2_) + }, + { + _instrCodesDb.Stelem_.Id, + new VmInstr(_instrCodesDb.Stelem_, Stelem_) + }, + { + _instrCodesDb.Ldind_r8_.Id, + new VmInstr(_instrCodesDb.Ldind_r8_, Ldind_r8_) + }, + { + _instrCodesDb.Ldc_r8_.Id, + new VmInstr(_instrCodesDb.Ldc_r8_, Ldc_r8_) + }, + { + _instrCodesDb.Bge_.Id, + new VmInstr(_instrCodesDb.Bge_, Bge_) + }, + { + _instrCodesDb.Ldind_i1_.Id, + new VmInstr(_instrCodesDb.Ldind_i1_, Ldind_i1_) + }, + { + _instrCodesDb.Ldelem_u1_.Id, + new VmInstr(_instrCodesDb.Ldelem_u1_, Ldelem_u1_) + }, + { + _instrCodesDb.Ldstr_.Id, + new VmInstr(_instrCodesDb.Ldstr_, Ldstr_) + }, + { + _instrCodesDb.Ldloca_s_.Id, + new VmInstr(_instrCodesDb.Ldloca_s_, Ldloca_s_) + }, + { + _instrCodesDb.Ldelem_i8_.Id, + new VmInstr(_instrCodesDb.Ldelem_i8_, Ldelem_i8_) + }, + { + _instrCodesDb.Ldc_i4_8_.Id, + new VmInstr(_instrCodesDb.Ldc_i4_8_, Ldc_i4_8_) + }, + { + _instrCodesDb.Blt_.Id, + new VmInstr(_instrCodesDb.Blt_, Blt_) + }, + { + _instrCodesDb.Unbox_.Id, + new VmInstr(_instrCodesDb.Unbox_, Unbox_) + }, + { + _instrCodesDb.Bge_un_.Id, + new VmInstr(_instrCodesDb.Bge_un_, Bge_un_) + }, + { + _instrCodesDb.Ldelem_u2_.Id, + new VmInstr(_instrCodesDb.Ldelem_u2_, Ldelem_u2_) + }, + { + _instrCodesDb.Ldind_u2_.Id, + new VmInstr(_instrCodesDb.Ldind_u2_, Ldind_u2_) + }, + { + _instrCodesDb.Sub_ovf_un_.Id, + new VmInstr(_instrCodesDb.Sub_ovf_un_, Sub_ovf_un_) + }, + { + _instrCodesDb.Ldc_i4_4_.Id, + new VmInstr(_instrCodesDb.Ldc_i4_4_, Ldc_i4_4_) + }, + { + _instrCodesDb.Ldarg_0_.Id, + new VmInstr(_instrCodesDb.Ldarg_0_, Ldarg_0_) + }, + { + _instrCodesDb.Rem_un_.Id, + new VmInstr(_instrCodesDb.Rem_un_, Rem_un_) + }, + { + _instrCodesDb.Ldloc_1_.Id, + new VmInstr(_instrCodesDb.Ldloc_1_, Ldloc_1_) + }, + { + _instrCodesDb.Bne_un_.Id, + new VmInstr(_instrCodesDb.Bne_un_, Bne_un_) + }, + { + _instrCodesDb.Conv_ovf_i2_un_.Id, + new VmInstr(_instrCodesDb.Conv_ovf_i2_un_, Conv_ovf_i2_un_) + }, + { + _instrCodesDb.Ckfinite_.Id, + new VmInstr(_instrCodesDb.Ckfinite_, Ckfinite_) + }, + { + _instrCodesDb.Ldobj_.Id, + new VmInstr(_instrCodesDb.Ldobj_, Ldobj_) + }, + { + _instrCodesDb.Pop_.Id, + new VmInstr(_instrCodesDb.Pop_, Pop_) + }, + { + _instrCodesDb.Constrained_.Id, + new VmInstr(_instrCodesDb.Constrained_, Constrained_) + }, + { + _instrCodesDb.Ldc_i4_s_.Id, + new VmInstr(_instrCodesDb.Ldc_i4_s_, Ldc_i4_s_) + }, + { + _instrCodesDb.Ldloc_s_.Id, + new VmInstr(_instrCodesDb.Ldloc_s_, Ldloc_s_) + }, + { + _instrCodesDb.Ldarg_2_.Id, + new VmInstr(_instrCodesDb.Ldarg_2_, Ldarg_2_) + }, + { + _instrCodesDb.Ldarga_.Id, + new VmInstr(_instrCodesDb.Ldarga_, Ldarga_) + }, + { + _instrCodesDb.Conv_i8_.Id, + new VmInstr(_instrCodesDb.Conv_i8_, Conv_i8_) + }, + { + _instrCodesDb.Br_.Id, + new VmInstr(_instrCodesDb.Br_, Br_) + }, + { + _instrCodesDb.Ldc_i4_3_.Id, + new VmInstr(_instrCodesDb.Ldc_i4_3_, Ldc_i4_3_) + }, + { + _instrCodesDb.Mul_ovf_.Id, + new VmInstr(_instrCodesDb.Mul_ovf_, Mul_ovf_) + }, + { + _instrCodesDb.Shl_.Id, + new VmInstr(_instrCodesDb.Shl_, Shl_) + }, + { + _instrCodesDb.Castclass_.Id, + new VmInstr(_instrCodesDb.Castclass_, Castclass_) + }, + { + _instrCodesDb.Jmp_.Id, + new VmInstr(_instrCodesDb.Jmp_, Jmp_) + }, + { + _instrCodesDb.Beq_.Id, + new VmInstr(_instrCodesDb.Beq_, Beq_) + }, + { + _instrCodesDb.Conv_r4_.Id, + new VmInstr(_instrCodesDb.Conv_r4_, Conv_r4_) + }, + { + _instrCodesDb.Ble_.Id, + new VmInstr(_instrCodesDb.Ble_, Ble_) + }, + { + _instrCodesDb.Conv_ovf_u2_un_.Id, + new VmInstr(_instrCodesDb.Conv_ovf_u2_un_, Conv_ovf_u2_un_) + }, + { + _instrCodesDb.Call_.Id, + new VmInstr(_instrCodesDb.Call_, Call_) + }, + { + _instrCodesDb.Not_.Id, + new VmInstr(_instrCodesDb.Not_, Not_) + } + }; + } + } + + // Token: 0x02000042 RID: 66 + public sealed class LocalVarType // \u0008 + { + // Token: 0x060002E4 RID: 740 RVA: 0x00013F08 File Offset: 0x00012108 + // Token: 0x060002E5 RID: 741 RVA: 0x00013F10 File Offset: 0x00012110 + // Token: 0x04000171 RID: 369 + public int TypeId /* \u0002 */ { get; set; } + } + + // Token: 0x0200004D RID: 77 + public sealed class ArgTypeToOutput // \u000E + { + // Token: 0x06000321 RID: 801 RVA: 0x00014C74 File Offset: 0x00012E74 + // Token: 0x06000322 RID: 802 RVA: 0x00014C7C File Offset: 0x00012E7C + // Token: 0x0400017C RID: 380 + public int TypeId /* \u0002 */ { get; set; } + + // Token: 0x06000323 RID: 803 RVA: 0x00014C88 File Offset: 0x00012E88 + // Token: 0x06000324 RID: 804 RVA: 0x00014C90 File Offset: 0x00012E90 + // Token: 0x0400017D RID: 381 + public bool IsOutput /* \u0003 */ { get; set; } + } + + // Token: 0x0200005E RID: 94 + internal sealed class CatchBlock + { + // Token: 0x0600036B RID: 875 RVA: 0x00015AFC File Offset: 0x00013CFC + // Token: 0x0600036C RID: 876 RVA: 0x00015B04 File Offset: 0x00013D04 + // Token: 0x04000189 RID: 393 + public byte Kind { get; set; } + + // Token: 0x0600036D RID: 877 RVA: 0x00015B10 File Offset: 0x00013D10 + // Token: 0x0600036E RID: 878 RVA: 0x00015B18 File Offset: 0x00013D18 + // Token: 0x0400018A RID: 394 + public int ExcTypeId { get; set; } + + // Token: 0x0600036F RID: 879 RVA: 0x00015B24 File Offset: 0x00013D24 + // Token: 0x06000370 RID: 880 RVA: 0x00015B2C File Offset: 0x00013D2C + // Token: 0x0400018B RID: 395 + public uint PosKind4 { get; set; } + + // Token: 0x06000371 RID: 881 RVA: 0x00015B38 File Offset: 0x00013D38 + // Token: 0x06000372 RID: 882 RVA: 0x00015B40 File Offset: 0x00013D40 + // Token: 0x0400018C RID: 396 + public uint Start { get; set; } + + // Token: 0x06000373 RID: 883 RVA: 0x00015B4C File Offset: 0x00013D4C + // Token: 0x06000374 RID: 884 RVA: 0x00015B54 File Offset: 0x00013D54 + // Token: 0x0400018D RID: 397 + public uint Pos { get; set; } // \u0005 + + // Token: 0x06000375 RID: 885 RVA: 0x00015B60 File Offset: 0x00013D60 + // Token: 0x06000376 RID: 886 RVA: 0x00015B68 File Offset: 0x00013D68 + // Token: 0x0400018E RID: 398 + public uint Len { get; set; } + } + + // Token: 0x02000049 RID: 73 + internal abstract class VmTokenInfo // \u0008\u2006 + { + internal enum Kind : byte + { + Class0, Field1, Method2, String3, MethodRef4 + } + + // Token: 0x0600030D RID: 781 + public abstract Kind TokenKind(); // \u0008\u2006\u2008\u2000\u2002\u200A\u0002 + } + + // Token: 0x02000017 RID: 23 + internal sealed class UniversalTokenInfo // \u0003\u2008 + { + // Token: 0x06000097 RID: 151 RVA: 0x00003E9C File Offset: 0x0000209C + // Token: 0x06000098 RID: 152 RVA: 0x00003EA4 File Offset: 0x000020A4 + // Token: 0x04000020 RID: 32 + public byte IsVm { get; set; } + + // Token: 0x06000099 RID: 153 RVA: 0x00003EB0 File Offset: 0x000020B0 + // Token: 0x0600009A RID: 154 RVA: 0x00003EB8 File Offset: 0x000020B8 + // Token: 0x04000021 RID: 33 + public int MetadataToken { get; set; } + + // Token: 0x0600009B RID: 155 RVA: 0x00003EC4 File Offset: 0x000020C4 + // Token: 0x0600009C RID: 156 RVA: 0x00003ECC File Offset: 0x000020CC + // Token: 0x04000022 RID: 34 + public VmTokenInfo VmToken { get; set; } + } + + // Token: 0x02000016 RID: 22 + internal sealed class VmMethodRefTokenInfo : VmTokenInfo // \u0003\u2007 + { + // Token: 0x06000091 RID: 145 RVA: 0x00003E68 File Offset: 0x00002068 + // Token: 0x06000092 RID: 146 RVA: 0x00003E70 File Offset: 0x00002070 + // Token: 0x0400001E RID: 30 + public int Flags { get; set; } + + // Token: 0x06000093 RID: 147 RVA: 0x00003E7C File Offset: 0x0000207C + // Token: 0x06000094 RID: 148 RVA: 0x00003E84 File Offset: 0x00002084 + // Token: 0x0400001F RID: 31 + public int Pos { get; set; } + + // Token: 0x06000095 RID: 149 RVA: 0x00003E90 File Offset: 0x00002090 + public override Kind TokenKind() // \u0008\u2006\u2008\u2000\u2002\u200A\u0002 + { + return Kind.MethodRef4; + } + } + + // Token: 0x0200004A RID: 74 + internal sealed class VmMethodTokenInfo : VmTokenInfo // \u0008\u2007 + { + // Token: 0x0600030F RID: 783 RVA: 0x00014BB0 File Offset: 0x00012DB0 + // Token: 0x06000310 RID: 784 RVA: 0x00014BB8 File Offset: 0x00012DB8 + // Token: 0x04000176 RID: 374 + public byte Flags { get; set; } + + // Token: 0x06000311 RID: 785 RVA: 0x00014BC4 File Offset: 0x00012DC4 + public bool IsStatic() // \u0002 + { + return (Flags & 2) > 0; + } + + // Token: 0x06000312 RID: 786 RVA: 0x00014BD4 File Offset: 0x00012DD4 + public bool IsGeneric() // \u0003 + { + return (Flags & 1) > 0; + } + + // Token: 0x06000313 RID: 787 RVA: 0x00014BE4 File Offset: 0x00012DE4 + // Token: 0x06000314 RID: 788 RVA: 0x00014BEC File Offset: 0x00012DEC + // Token: 0x04000177 RID: 375 + public UniversalTokenInfo Class { get; set; } + + // Token: 0x06000315 RID: 789 RVA: 0x00014BF8 File Offset: 0x00012DF8 + // Token: 0x06000316 RID: 790 RVA: 0x00014C00 File Offset: 0x00012E00 + // Token: 0x04000178 RID: 376 + public string Name { get; set; } + + // Token: 0x06000317 RID: 791 RVA: 0x00014C0C File Offset: 0x00012E0C + // Token: 0x06000318 RID: 792 RVA: 0x00014C14 File Offset: 0x00012E14 + // Token: 0x04000179 RID: 377 + public UniversalTokenInfo[] Parameters { get; set; } + + // Token: 0x06000319 RID: 793 RVA: 0x00014C20 File Offset: 0x00012E20 + // Token: 0x0600031A RID: 794 RVA: 0x00014C28 File Offset: 0x00012E28 + // Token: 0x0400017A RID: 378 + public UniversalTokenInfo[] GenericArguments { get; set; } + + // Token: 0x0600031B RID: 795 RVA: 0x00014C34 File Offset: 0x00012E34 + // Token: 0x0600031C RID: 796 RVA: 0x00014C3C File Offset: 0x00012E3C + // Token: 0x0400017B RID: 379 + public UniversalTokenInfo ReturnType { get; set; } + + // Token: 0x0600031D RID: 797 RVA: 0x00014C48 File Offset: 0x00012E48 + public override Kind TokenKind() // \u0008\u2006\u2008\u2000\u2002\u200A\u0002 + { + return Kind.Method2; + } + } + + // Token: 0x02000056 RID: 86 + internal sealed class VmStringTokenInfo : VmTokenInfo // \u000E\u2007 + { + // Token: 0x06000343 RID: 835 RVA: 0x000153CC File Offset: 0x000135CC + // Token: 0x06000344 RID: 836 RVA: 0x000153D4 File Offset: 0x000135D4 + // Token: 0x04000185 RID: 389 + public string Value { get; set; } + + // Token: 0x06000345 RID: 837 RVA: 0x000153E0 File Offset: 0x000135E0 + public override Kind TokenKind() // \u0008\u2006\u2008\u2000\u2002\u200A\u0002 + { + return Kind.String3; + } + } + + // Token: 0x02000060 RID: 96 + internal sealed class VmFieldTokenInfo : VmTokenInfo // \u000F\u2006 + { + // Token: 0x06000382 RID: 898 RVA: 0x00015C38 File Offset: 0x00013E38 + // Token: 0x06000383 RID: 899 RVA: 0x00015C40 File Offset: 0x00013E40 + // Token: 0x04000191 RID: 401 + public UniversalTokenInfo Class { get; set; } + + // Token: 0x06000384 RID: 900 RVA: 0x00015C4C File Offset: 0x00013E4C + // Token: 0x06000385 RID: 901 RVA: 0x00015C54 File Offset: 0x00013E54 + // Token: 0x04000192 RID: 402 + public string Name { get; set; } + + // Token: 0x06000386 RID: 902 RVA: 0x00015C60 File Offset: 0x00013E60 + // Token: 0x06000387 RID: 903 RVA: 0x00015C68 File Offset: 0x00013E68 + // Token: 0x04000193 RID: 403 + public bool IsStatic { get; set; } + + // Token: 0x06000388 RID: 904 RVA: 0x00015C74 File Offset: 0x00013E74 + public override Kind TokenKind() // \u0008\u2006\u2008\u2000\u2002\u200A\u0002 + { + return Kind.Field1; + } + } + + // Token: 0x02000061 RID: 97 + internal sealed class VmClassTokenInfo : VmTokenInfo // \u000F\u2007 + { + // Token: 0x04000194 RID: 404 + // Token: 0x0600038A RID: 906 RVA: 0x00015C90 File Offset: 0x00013E90 + // Token: 0x0600038B RID: 907 RVA: 0x00015C98 File Offset: 0x00013E98 + public string ClassName { get; set; } + + // Token: 0x0600038C RID: 908 RVA: 0x00015CA4 File Offset: 0x00013EA4 + // Token: 0x04000195 RID: 405 + // Token: 0x0600038D RID: 909 RVA: 0x00015CAC File Offset: 0x00013EAC + public bool IsOuterClassGeneric { get; set; } + + // Token: 0x0600038E RID: 910 RVA: 0x00015CB8 File Offset: 0x00013EB8 + // Token: 0x04000196 RID: 406 + // Token: 0x0600038F RID: 911 RVA: 0x00015CC0 File Offset: 0x00013EC0 + public bool IsGeneric { get; set; } + + // Token: 0x06000390 RID: 912 RVA: 0x00015CCC File Offset: 0x00013ECC + // Token: 0x04000197 RID: 407 + // Token: 0x06000391 RID: 913 RVA: 0x00015CD4 File Offset: 0x00013ED4 + public UniversalTokenInfo[] GenericArguments { get; set; } + + // Token: 0x06000392 RID: 914 RVA: 0x00015CE0 File Offset: 0x00013EE0 + // Token: 0x04000198 RID: 408 + // Token: 0x06000393 RID: 915 RVA: 0x00015CE8 File Offset: 0x00013EE8 + public int OuterClassGenericClassIdx { get; set; } = -1; + + // Token: 0x06000394 RID: 916 RVA: 0x00015CF4 File Offset: 0x00013EF4 + // Token: 0x04000199 RID: 409 + // Token: 0x06000395 RID: 917 RVA: 0x00015CFC File Offset: 0x00013EFC + public int OuterClassGenericMethodIdx { get; set; } = -1; + + // Token: 0x06000396 RID: 918 RVA: 0x00015D08 File Offset: 0x00013F08 + public override Kind TokenKind() // \u0008\u2006\u2008\u2000\u2002\u200A\u0002 + { + return Kind.Class0; + } + } +} diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VmInstrCodesDb.cs b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VmInstrCodesDb.cs new file mode 100644 index 0000000..0ca16de --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VmInstrCodesDb.cs @@ -0,0 +1,899 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Threading; + +// ReSharper disable UnusedMember.Global + +namespace UnitTestProject.RefVm +{ + // Token: 0x0200002E RID: 46 + [SuppressMessage("ReSharper", "InconsistentNaming")] + public class VmInstrCodesDb // \u0006\u2005 + { + // Token: 0x04000068 RID: 104 + private VmInstrInfo[] _all; + + // Token: 0x0400011D RID: 285 + private bool _initialized; + + // Token: 0x0600015B RID: 347 RVA: 0x000075B8 File Offset: 0x000057B8 + public bool IsInitialized() // \u0002 + { + return _initialized; + } + + // Token: 0x0600015C RID: 348 RVA: 0x000075C0 File Offset: 0x000057C0 + public void SetInitialized(bool val) // \u0002 + { + _initialized = val; + } + + // Token: 0x0600015A RID: 346 RVA: 0x000075A8 File Offset: 0x000057A8 + public IEnumerable<VmInstrInfo> MyFieldsEnumerator() // \u0002 + { + return new FieldsEnumerator(-2) + { + Source = this + }; + } + + // Token: 0x0600015D RID: 349 RVA: 0x000075CC File Offset: 0x000057CC + public VmInstrInfo[] ToSortedArray() // \u0002 + { + if (_all == null) + { + lock (this) + { + if (_all == null) + { + var list = new List<VmInstrInfo>(256); + list.AddRange(MyFieldsEnumerator()); + if (SortHelper.MyComparison == null) + { + SortHelper.MyComparison = SortHelper.MySortHelper.Compare; + } + list.Sort(SortHelper.MyComparison); + _all = list.ToArray(); + } + } + } + return _all; + } + + // Token: 0x0200002F RID: 47 + [Serializable] + private sealed class SortHelper // \u0002 + { + // Token: 0x06000160 RID: 352 RVA: 0x000076A0 File Offset: 0x000058A0 + internal int Compare(VmInstrInfo v1, VmInstrInfo v2) // \u0002 + { + return v1.Id.CompareTo(v2.Id); + } + + // Token: 0x04000129 RID: 297 + public static readonly SortHelper MySortHelper = new SortHelper(); // \u0002 + + // Token: 0x0400012A RID: 298 + public static Comparison<VmInstrInfo> MyComparison; // \u0003 + } + + // Token: 0x02000030 RID: 48 + private sealed class FieldsEnumerator : IEnumerable<VmInstrInfo>, IEnumerator<VmInstrInfo> // \u0003 + { + // Token: 0x06000161 RID: 353 RVA: 0x000076C4 File Offset: 0x000058C4 + public FieldsEnumerator(int st) + { + _state = st; + _threadId = Thread.CurrentThread.ManagedThreadId; + } + + // Token: 0x06000162 RID: 354 RVA: 0x000076E4 File Offset: 0x000058E4 + void IDisposable.Dispose() // \u0003\u2008\u2000\u2002\u200A\u0002 + { + } + + // Token: 0x06000163 RID: 355 RVA: 0x000076E8 File Offset: 0x000058E8 + bool IEnumerator.MoveNext() + { + var num = _state; + if (num != 0) + { + if (num != 1) + { + return false; + } + _state = -1; + _index++; + } + else + { + _state = -1; + var fields = typeof(VmInstrCodesDb).GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public); + _data = fields; + _index = 0; + } + if (_index >= _data.Length) + { + _data = null; + return false; + } + var p = (VmInstrInfo)_data[_index].GetValue(Source); + _current = p; + _state = 1; + return true; + } + + // Token: 0x06000164 RID: 356 RVA: 0x00007790 File Offset: 0x00005990 + VmInstrInfo IEnumerator<VmInstrInfo>.Current // \u0003\u2008\u2000\u2002\u200A\u0002 + => _current; + + // Token: 0x06000165 RID: 357 RVA: 0x00007798 File Offset: 0x00005998 + [DebuggerHidden] + void IEnumerator.Reset() // \u0003\u2008\u2000\u2002\u200A\u0003 + { + throw new NotSupportedException(); + } + + // Token: 0x06000166 RID: 358 RVA: 0x000077A0 File Offset: 0x000059A0 + [DebuggerHidden] + object IEnumerator.Current // \u0003\u2008\u2000\u2002\u200A\u0002 + => _current; + + // Token: 0x06000167 RID: 359 RVA: 0x000077A8 File Offset: 0x000059A8 + [DebuggerHidden] + IEnumerator<VmInstrInfo> IEnumerable<VmInstrInfo>.GetEnumerator() // \u0003\u2008\u2000\u2002\u200A\u0002 + { + FieldsEnumerator ret; + if (_state == -2 && _threadId == Thread.CurrentThread.ManagedThreadId) + { + _state = 0; + ret = this; + } + else + { + ret = new FieldsEnumerator(0) {Source = Source}; + } + return ret; + } + + // Token: 0x06000168 RID: 360 RVA: 0x000077F0 File Offset: 0x000059F0 + [DebuggerHidden] + IEnumerator IEnumerable.GetEnumerator() // \u0003\u2008\u2000\u2002\u200A\u0002 + { + return ((IEnumerable<VmInstrInfo>)this).GetEnumerator(); + } + + // Token: 0x0400012B RID: 299 + private int _state; // \u0002 + + // Token: 0x0400012C RID: 300 + private VmInstrInfo _current; // \u0003 + + // Token: 0x0400012D RID: 301 + private readonly int _threadId; // \u0005 + + // Token: 0x0400012E RID: 302 + public VmInstrCodesDb Source; // \u0008 + + // Token: 0x0400012F RID: 303 + private FieldInfo[] _data; // \u0006 + + // Token: 0x04000130 RID: 304 + private int _index; // \u000E + } + + #region all + /* +no. { typecheck, rangecheck, nullcheck } The specified fault check(s) normally performed as part of the execution of the subsequent instruction can/shall be skipped. Prefix to instruction +readonly. Specify that the subsequent array address operation performs no type check at runtime, and that it returns a controlled-mutability managed pointer Prefix to instruction +tail. Subsequent call terminates current method Prefix to instruction +unaligned. (alignment) Subsequent pointer instruction might be unaligned. Prefix to instruction +volatile. Subsequent pointer reference is volatile. Prefix to instruction + */ + // Token: 0x04000063 RID: 99 + public readonly VmInstrInfo U0002U2000 = new VmInstrInfo(690984147, VmOperandType.Ot11Nope); // not implemented + + // Token: 0x04000077 RID: 119 + public readonly VmInstrInfo U0006U2001U2000 = new VmInstrInfo(733028785, VmOperandType.Ot11Nope); // not implemented + + // Token: 0x0400007A RID: 122 + public readonly VmInstrInfo U0006U2001 = new VmInstrInfo(701247957, VmOperandType.Ot11Nope); // not implemented + + // Token: 0x04000086 RID: 134 + public readonly VmInstrInfo U0006U2004 = new VmInstrInfo(-377358754, VmOperandType.Ot11Nope); // not implemented + + // Token: 0x040000B0 RID: 176 + public readonly VmInstrInfo U0006U2008U2000 = new VmInstrInfo(1026942272, VmOperandType.Ot11Nope); // empty impl + + // Token: 0x040000B2 RID: 178 + public readonly VmInstrInfo Endfilter_ = new VmInstrInfo(-1041717787, VmOperandType.Ot11Nope); + + // Token: 0x040000C6 RID: 198 + public readonly VmInstrInfo Mul_ovf_ = new VmInstrInfo(717697778, VmOperandType.Ot11Nope); + + // Token: 0x040000CB RID: 203 + public readonly VmInstrInfo Endfinally_ = new VmInstrInfo(-860175516, VmOperandType.Ot11Nope); + + // Token: 0x040000E0 RID: 224 + public readonly VmInstrInfo U0003U2009 = new VmInstrInfo(-1535884281, VmOperandType.Ot11Nope); // not implemented + + // Token: 0x04000080 RID: 128 + public readonly VmInstrInfo U000EU2006U2000 = new VmInstrInfo(1756761351, VmOperandType.Ot5Int); // ??? invoke some method + + // Token: 0x04000082 RID: 130 + public readonly VmInstrInfo Jmp_ = new VmInstrInfo(-512817309, VmOperandType.Ot12Int); + + // Token: 0x040000CC RID: 204 + public readonly VmInstrInfo Initobj_ = new VmInstrInfo(-647649665, VmOperandType.Ot5Int); + + // Token: 0x04000065 RID: 101 + public readonly VmInstrInfo Calli_ = new VmInstrInfo(1295283437, VmOperandType.Ot5Int); + + // Token: 0x0400006F RID: 111 + public readonly VmInstrInfo Constrained_ = new VmInstrInfo(1803463719, VmOperandType.Ot5Int); + + // Token: 0x04000098 RID: 152 + public readonly VmInstrInfo U000FU2001 = new VmInstrInfo(-1952417400, VmOperandType.Ot5Int); // empty impl + + // Token: 0x040000E1 RID: 225 + public readonly VmInstrInfo Box_ = new VmInstrInfo(1491096114, VmOperandType.Ot5Int); + + // Token: 0x040000E4 RID: 228 + public readonly VmInstrInfo U0006U200BU2000 = new VmInstrInfo(-1858492701, VmOperandType.Ot11Nope); // not implemented + + // Token: 0x040000ED RID: 237 + public readonly VmInstrInfo U0002U2002U2001 = new VmInstrInfo(113196648, VmOperandType.Ot11Nope); // not implemented + + // Token: 0x040000EF RID: 239 + public readonly VmInstrInfo Ldobj_ = new VmInstrInfo(-564585233, VmOperandType.Ot5Int); + + // Token: 0x04000104 RID: 260 + public readonly VmInstrInfo Rethrow_ = new VmInstrInfo(989001448, VmOperandType.Ot11Nope); + + // Token: 0x04000125 RID: 293 + public readonly VmInstrInfo U000EU2000U2000 = new VmInstrInfo(814546329, VmOperandType.Ot11Nope); // not implemented + + // Token: 0x040000B8 RID: 184 + public readonly VmInstrInfo Newobj_ = new VmInstrInfo(783240206, VmOperandType.Ot5Int); + + // Token: 0x040000B9 RID: 185 + public readonly VmInstrInfo U0006U2000U2000 = new VmInstrInfo(569679686, VmOperandType.Ot11Nope); // not implemented + + // Token: 0x040000BD RID: 189 + public readonly VmInstrInfo U0002U200B = new VmInstrInfo(578506051, VmOperandType.Ot6SByte); // leave.s not implemented + + // Token: 0x040000BE RID: 190 + public readonly VmInstrInfo Leave_ = new VmInstrInfo(182069479, VmOperandType.Ot0UInt); + + // Token: 0x040000B3 RID: 179 + //public readonly VmInstrInfo U0003U2008 = new VmInstrInfo(56035065, VmOperandType.Nope11); + + // Token: 0x04000052 RID: 82 + public readonly VmInstrInfo Ldnull_ = new VmInstrInfo(1672432034, VmOperandType.Ot11Nope); + + // Token: 0x04000057 RID: 87 + public readonly VmInstrInfo Pop_ = new VmInstrInfo(-423590017, VmOperandType.Ot11Nope); + + // Token: 0x0400005B RID: 91 + public readonly VmInstrInfo Ckfinite_ = new VmInstrInfo(-624596400, VmOperandType.Ot11Nope); + + // Token: 0x0400005D RID: 93 + public readonly VmInstrInfo Stind_i2_ = new VmInstrInfo(81292670, VmOperandType.Ot11Nope); + + // Token: 0x0400006C RID: 108 + public readonly VmInstrInfo Stind_r8_ = new VmInstrInfo(-239256528, VmOperandType.Ot11Nope); + + // Token: 0x04000074 RID: 116 + public readonly VmInstrInfo Ldftn_ = new VmInstrInfo(-204727488, VmOperandType.Ot5Int); + + // Token: 0x04000076 RID: 118 + public readonly VmInstrInfo Ldlen_ = new VmInstrInfo(-1528794514, VmOperandType.Ot11Nope); + + // Token: 0x04000079 RID: 121 + public readonly VmInstrInfo Isinst_ = new VmInstrInfo(-1879745689, VmOperandType.Ot5Int); + + // Token: 0x04000081 RID: 129 + public readonly VmInstrInfo Stind_i8_ = new VmInstrInfo(-279385973, VmOperandType.Ot11Nope); + + // Token: 0x04000087 RID: 135 + public readonly VmInstrInfo Newarr_ = new VmInstrInfo(1211659810, VmOperandType.Ot5Int); + + // Token: 0x04000089 RID: 137 + public readonly VmInstrInfo Callvirt_ = new VmInstrInfo(497685394, VmOperandType.Ot5Int); + + // Token: 0x0400008A RID: 138 + public readonly VmInstrInfo Ldc_i8_ = new VmInstrInfo(598097099, VmOperandType.Ot7Long); + + // Token: 0x0400009A RID: 154 + public readonly VmInstrInfo Castclass_ = new VmInstrInfo(1816382558, VmOperandType.Ot5Int); + + // Token: 0x0400009C RID: 156 + public readonly VmInstrInfo Stind_i_ = new VmInstrInfo(-774914583, VmOperandType.Ot11Nope); + + // Token: 0x0400009D RID: 157 + public readonly VmInstrInfo Ldc_i4_s_ = new VmInstrInfo(1440000960, VmOperandType.Ot6SByte); + + // Token: 0x040000A7 RID: 167 + public readonly VmInstrInfo Not_ = new VmInstrInfo(2044815068, VmOperandType.Ot11Nope); + + // Token: 0x040000A8 RID: 168 + public readonly VmInstrInfo Ldtoken_ = new VmInstrInfo(757747961, VmOperandType.Ot5Int); + + // Token: 0x040000AD RID: 173 + public readonly VmInstrInfo Stind_i4_ = new VmInstrInfo(-587303415, VmOperandType.Ot11Nope); + + // Token: 0x040000B6 RID: 182 + public readonly VmInstrInfo Ldvirtftn_ = new VmInstrInfo(-1088007919, VmOperandType.Ot5Int); + + // Token: 0x040000BA RID: 186 + public readonly VmInstrInfo Stind_i1_ = new VmInstrInfo(122987244, VmOperandType.Ot11Nope); + + // Token: 0x040000BC RID: 188 + public readonly VmInstrInfo Cgt_ = new VmInstrInfo(-290816002, VmOperandType.Ot11Nope); + + // Token: 0x040000C4 RID: 196 + public readonly VmInstrInfo Stobj_ = new VmInstrInfo(-18831398, VmOperandType.Ot5Int); + + // Token: 0x040000C5 RID: 197 + public readonly VmInstrInfo Clt_un_ = new VmInstrInfo(-377042092, VmOperandType.Ot11Nope); + + // Token: 0x040000DD RID: 221 + public readonly VmInstrInfo Cgt_un_ = new VmInstrInfo(-244421767, VmOperandType.Ot11Nope); + + // Token: 0x040000D6 RID: 214 + public readonly VmInstrInfo Stind_ref_ = new VmInstrInfo(-572078212, VmOperandType.Ot11Nope); + + // Token: 0x040000DF RID: 223 + public readonly VmInstrInfo Ldloca_ = new VmInstrInfo(-1112986259, VmOperandType.Ot1UShort); + + // Token: 0x040000E9 RID: 233 + public readonly VmInstrInfo Call_ = new VmInstrInfo(-1118186024, VmOperandType.Ot5Int); + + // Token: 0x040000F9 RID: 249 + public readonly VmInstrInfo Ldc_r8_ = new VmInstrInfo(-557730397, VmOperandType.Ot4Double); + + // Token: 0x040000FD RID: 253 + public readonly VmInstrInfo Clt_ = new VmInstrInfo(-1789431058, VmOperandType.Ot11Nope); + + // Token: 0x04000107 RID: 263 + public readonly VmInstrInfo Ldc_i4_ = new VmInstrInfo(-763377227, VmOperandType.Ot12Int); + + // Token: 0x04000112 RID: 274 + public readonly VmInstrInfo Ldc_r4_ = new VmInstrInfo(-976252990, VmOperandType.Ot10Float); + + // Token: 0x04000116 RID: 278 + public readonly VmInstrInfo Stind_r4_ = new VmInstrInfo(2036802079, VmOperandType.Ot11Nope); + + // Token: 0x04000119 RID: 281 + public readonly VmInstrInfo Nop_ = new VmInstrInfo(-724560934, VmOperandType.Ot11Nope); + + // Token: 0x0400011E RID: 286 + public readonly VmInstrInfo Ldloca_s_ = new VmInstrInfo(1851592203, VmOperandType.Ot8Byte); + + // Token: 0x04000053 RID: 83 + public readonly VmInstrInfo Sizeof_ = new VmInstrInfo(-1163259743, VmOperandType.Ot5Int); + + // Token: 0x04000054 RID: 84 + public readonly VmInstrInfo Ldind_r4_ = new VmInstrInfo(1144322863, VmOperandType.Ot11Nope); + + // Token: 0x04000055 RID: 85 + public readonly VmInstrInfo Ldelem_i1_ = new VmInstrInfo(322204500, VmOperandType.Ot11Nope); + + // Token: 0x04000056 RID: 86 + public readonly VmInstrInfo Conv_r8_ = new VmInstrInfo(-195608730, VmOperandType.Ot11Nope); + + // Token: 0x04000058 RID: 88 + public readonly VmInstrInfo Stelem_i1_ = new VmInstrInfo(-1560659480, VmOperandType.Ot11Nope); + + // Token: 0x04000059 RID: 89 + public readonly VmInstrInfo Ldstr_ = new VmInstrInfo(-883753595, VmOperandType.Ot5Int); + + // Token: 0x0400005A RID: 90 + public readonly VmInstrInfo Conv_i4_ = new VmInstrInfo(1738936149, VmOperandType.Ot11Nope); + + // Token: 0x0400005C RID: 92 + public readonly VmInstrInfo Ldarg_2_ = new VmInstrInfo(917707539, VmOperandType.Ot11Nope); + + // Token: 0x0400005E RID: 94 + public readonly VmInstrInfo Conv_i1_ = new VmInstrInfo(443736782, VmOperandType.Ot11Nope); + + // Token: 0x0400005F RID: 95 + public readonly VmInstrInfo Div_ = new VmInstrInfo(873071583, VmOperandType.Ot11Nope); + + // Token: 0x04000060 RID: 96 + public readonly VmInstrInfo Conv_i_ = new VmInstrInfo(863451657, VmOperandType.Ot11Nope); + + // Token: 0x04000061 RID: 97 + public readonly VmInstrInfo Stelem_ref_ = new VmInstrInfo(1243606418, VmOperandType.Ot11Nope); + + // Token: 0x04000062 RID: 98 + public readonly VmInstrInfo Shl_ = new VmInstrInfo(1269228253, VmOperandType.Ot11Nope); + + // Token: 0x04000064 RID: 100 + public readonly VmInstrInfo Conv_u4_ = new VmInstrInfo(-1046006878, VmOperandType.Ot11Nope); + + // Token: 0x04000066 RID: 102 + public readonly VmInstrInfo Break_ = new VmInstrInfo(-979485219, VmOperandType.Ot11Nope); + + // Token: 0x04000067 RID: 103 + public readonly VmInstrInfo Ldc_i4_1_ = new VmInstrInfo(-2108713475, VmOperandType.Ot11Nope); + + // Token: 0x04000069 RID: 105 + public readonly VmInstrInfo Or_ = new VmInstrInfo(1569462844, VmOperandType.Ot11Nope); + + // Token: 0x0400006A RID: 106 + public readonly VmInstrInfo Ldelem_ = new VmInstrInfo(-1705118555, VmOperandType.Ot5Int); + + // Token: 0x0400006B RID: 107 + public readonly VmInstrInfo Conv_u1_ = new VmInstrInfo(1055970854, VmOperandType.Ot11Nope); + + // Token: 0x0400006D RID: 109 + public readonly VmInstrInfo Ldind_i1_ = new VmInstrInfo(33169414, VmOperandType.Ot11Nope); + + // Token: 0x0400006E RID: 110 + public readonly VmInstrInfo Ldind_i_ = new VmInstrInfo(-1790442498, VmOperandType.Ot11Nope); + + // Token: 0x04000070 RID: 112 + public readonly VmInstrInfo Ldsfld_ = new VmInstrInfo(-1369658342, VmOperandType.Ot5Int); + + // Token: 0x04000071 RID: 113 + public readonly VmInstrInfo Ldloc_ = new VmInstrInfo(766115889, VmOperandType.Ot1UShort); + + // Token: 0x04000072 RID: 114 + public readonly VmInstrInfo Rem_un_ = new VmInstrInfo(-2121309775, VmOperandType.Ot11Nope); + + // Token: 0x04000073 RID: 115 + public readonly VmInstrInfo Conv_ovf_i8_ = new VmInstrInfo(-287049786, VmOperandType.Ot11Nope); + + // Token: 0x04000075 RID: 117 + public readonly VmInstrInfo Ldc_i4_0_ = new VmInstrInfo(89715609, VmOperandType.Ot11Nope); + + // Token: 0x04000078 RID: 120 + public readonly VmInstrInfo Ldloc_3_ = new VmInstrInfo(1790654656, VmOperandType.Ot11Nope); + + // Token: 0x0400007B RID: 123 + public readonly VmInstrInfo Ldsflda_ = new VmInstrInfo(-2097007575, VmOperandType.Ot5Int); + + // Token: 0x0400007C RID: 124 + public readonly VmInstrInfo Add_ovf_ = new VmInstrInfo(-545700640, VmOperandType.Ot11Nope); + + // Token: 0x0400007D RID: 125 + public readonly VmInstrInfo Refanytype_ = new VmInstrInfo(-971088331, VmOperandType.Ot11Nope); + + // Token: 0x0400007E RID: 126 + public readonly VmInstrInfo Blt_ = new VmInstrInfo(1978323310, VmOperandType.Ot0UInt); + + // Token: 0x0400007F RID: 127 + public readonly VmInstrInfo Conv_ovf_u8_un_ = new VmInstrInfo(1527584358, VmOperandType.Ot11Nope); + + // Token: 0x04000083 RID: 131 + public readonly VmInstrInfo Ldelem_i8_ = new VmInstrInfo(1272142104, VmOperandType.Ot11Nope); + + // Token: 0x04000084 RID: 132 + public readonly VmInstrInfo Ldc_i4_6_ = new VmInstrInfo(871172961, VmOperandType.Ot11Nope); + + // Token: 0x04000085 RID: 133 + public readonly VmInstrInfo Starg_s_ = new VmInstrInfo(-687376789, VmOperandType.Ot8Byte); + + // Token: 0x04000088 RID: 136 + public readonly VmInstrInfo Beq_ = new VmInstrInfo(352236975, VmOperandType.Ot0UInt); + + // Token: 0x0400008B RID: 139 + public readonly VmInstrInfo Ldfld_ = new VmInstrInfo(-688284774, VmOperandType.Ot5Int); + + // Token: 0x0400008C RID: 140 + public readonly VmInstrInfo Conv_ovf_i2_un_ = new VmInstrInfo(1663762471, VmOperandType.Ot11Nope); + + // Token: 0x0400008D RID: 141 + public readonly VmInstrInfo Conv_ovf_i_un_ = new VmInstrInfo(2093357171, VmOperandType.Ot11Nope); + + // Token: 0x0400008E RID: 142 + public readonly VmInstrInfo Ldelem_u4_ = new VmInstrInfo(896332376, VmOperandType.Ot11Nope); + + // Token: 0x0400008F RID: 143 + public readonly VmInstrInfo Conv_ovf_u4_un_ = new VmInstrInfo(-107488823, VmOperandType.Ot11Nope); + + // Token: 0x04000090 RID: 144 + public readonly VmInstrInfo Ldarga_ = new VmInstrInfo(2044160323, VmOperandType.Ot1UShort); + + // Token: 0x04000091 RID: 145 + public readonly VmInstrInfo Div_un_ = new VmInstrInfo(742839562, VmOperandType.Ot11Nope); + + // Token: 0x04000092 RID: 146 + public readonly VmInstrInfo Ldelem_r4_ = new VmInstrInfo(-1447311583, VmOperandType.Ot11Nope); + + // Token: 0x04000093 RID: 147 + public readonly VmInstrInfo And_ = new VmInstrInfo(1968373082, VmOperandType.Ot11Nope); + + // Token: 0x04000094 RID: 148 + public readonly VmInstrInfo Add_ = new VmInstrInfo(-1892228817, VmOperandType.Ot11Nope); + + // Token: 0x04000095 RID: 149 + public readonly VmInstrInfo Conv_ovf_u2_ = new VmInstrInfo(1775410326, VmOperandType.Ot11Nope); + + // Token: 0x04000096 RID: 150 + public readonly VmInstrInfo Xor_ = new VmInstrInfo(-273395395, VmOperandType.Ot11Nope); + + // Token: 0x04000097 RID: 151 + public readonly VmInstrInfo Stloc_1_ = new VmInstrInfo(-1446892238, VmOperandType.Ot11Nope); + + // Token: 0x04000099 RID: 153 + public readonly VmInstrInfo Conv_ovf_u2_un_ = new VmInstrInfo(-1274139658, VmOperandType.Ot11Nope); + + // Token: 0x0400009B RID: 155 + public readonly VmInstrInfo Ldc_i4_3_ = new VmInstrInfo(-722334296, VmOperandType.Ot11Nope); + + // Token: 0x0400009E RID: 158 + public readonly VmInstrInfo Ldelem_u1_ = new VmInstrInfo(580121148, VmOperandType.Ot11Nope); + + // Token: 0x0400009F RID: 159 + public readonly VmInstrInfo Ldelem_i4_ = new VmInstrInfo(778369289, VmOperandType.Ot11Nope); + + // Token: 0x040000A0 RID: 160 + public readonly VmInstrInfo Stfld_ = new VmInstrInfo(1721102239, VmOperandType.Ot5Int); + + // Token: 0x040000A1 RID: 161 + public readonly VmInstrInfo Ldc_i4_m1_ = new VmInstrInfo(-1374936951, VmOperandType.Ot11Nope); + + // Token: 0x040000A2 RID: 162 + public readonly VmInstrInfo Brfalse_ = new VmInstrInfo(476056811, VmOperandType.Ot0UInt); + + // Token: 0x040000A3 RID: 163 + public readonly VmInstrInfo Rem_ = new VmInstrInfo(1127773841, VmOperandType.Ot11Nope); + + // Token: 0x040000A4 RID: 164 + public readonly VmInstrInfo Neg_ = new VmInstrInfo(1824866698, VmOperandType.Ot11Nope); + + // Token: 0x040000A5 RID: 165 + public readonly VmInstrInfo Initblk_ = new VmInstrInfo(1848160160, VmOperandType.Ot11Nope); + + // Token: 0x040000A6 RID: 166 + public readonly VmInstrInfo Ldelem_r8_ = new VmInstrInfo(-522987252, VmOperandType.Ot11Nope); + + // Token: 0x040000A9 RID: 169 + public readonly VmInstrInfo Cpobj_ = new VmInstrInfo(1238115537, VmOperandType.Ot5Int); + + // Token: 0x040000AA RID: 170 + public readonly VmInstrInfo Ldarga_s_ = new VmInstrInfo(-1193068213, VmOperandType.Ot8Byte); + + // Token: 0x040000AB RID: 171 + public readonly VmInstrInfo Br_ = new VmInstrInfo(658728581, VmOperandType.Ot0UInt); + + // Token: 0x040000AC RID: 172 + public readonly VmInstrInfo Conv_u2_ = new VmInstrInfo(-2099750455, VmOperandType.Ot11Nope); + + // Token: 0x040000AE RID: 174 + public readonly VmInstrInfo Stelem_i_ = new VmInstrInfo(-358560507, VmOperandType.Ot11Nope); + + // Token: 0x040000AF RID: 175 + public readonly VmInstrInfo Stloc_s_ = new VmInstrInfo(1804315644, VmOperandType.Ot8Byte); + + // Token: 0x040000B1 RID: 177 + public readonly VmInstrInfo Ble_un_ = new VmInstrInfo(1001656673, VmOperandType.Ot0UInt); + + // Token: 0x040000B4 RID: 180 + public readonly VmInstrInfo Ldc_i4_2_ = new VmInstrInfo(-2082446517, VmOperandType.Ot11Nope); + + // Token: 0x040000B5 RID: 181 + public readonly VmInstrInfo Blt_un_ = new VmInstrInfo(-1002275164, VmOperandType.Ot0UInt); + + // Token: 0x040000B7 RID: 183 + public readonly VmInstrInfo Ldind_ref_ = new VmInstrInfo(-101579585, VmOperandType.Ot11Nope); + + // Token: 0x040000BB RID: 187 + public readonly VmInstrInfo Ldind_i2_ = new VmInstrInfo(1338544134, VmOperandType.Ot11Nope); + + // Token: 0x040000BF RID: 191 + public readonly VmInstrInfo Shr_ = new VmInstrInfo(2061114403, VmOperandType.Ot11Nope); + + // Token: 0x040000C0 RID: 192 + public readonly VmInstrInfo Sub_ovf_ = new VmInstrInfo(-1326124455, VmOperandType.Ot11Nope); + + // Token: 0x040000C1 RID: 193 + public readonly VmInstrInfo Mul_ = new VmInstrInfo(-368354161, VmOperandType.Ot11Nope); + + // Token: 0x040000C2 RID: 194 + public readonly VmInstrInfo Conv_r4_ = new VmInstrInfo(461467744, VmOperandType.Ot11Nope); + + // Token: 0x040000C3 RID: 195 + public readonly VmInstrInfo Ldarg_s_ = new VmInstrInfo(916919316, VmOperandType.Ot8Byte); + + // Token: 0x040000C7 RID: 199 + public readonly VmInstrInfo Conv_ovf_u8_ = new VmInstrInfo(-1916788012, VmOperandType.Ot11Nope); + + // Token: 0x040000C8 RID: 200 + public readonly VmInstrInfo Ldind_u2_ = new VmInstrInfo(-1831891367, VmOperandType.Ot11Nope); + + // Token: 0x040000C9 RID: 201 + public readonly VmInstrInfo Ldind_u4_ = new VmInstrInfo(-1620795876, VmOperandType.Ot11Nope); + + // Token: 0x040000CA RID: 202 + public readonly VmInstrInfo Conv_ovf_i4_ = new VmInstrInfo(488024265, VmOperandType.Ot11Nope); + + // Token: 0x040000CD RID: 205 + public readonly VmInstrInfo Ldarg_1_ = new VmInstrInfo(326597331, VmOperandType.Ot11Nope); + + // Token: 0x040000CE RID: 206 + public readonly VmInstrInfo Conv_ovf_u_ = new VmInstrInfo(115989675, VmOperandType.Ot11Nope); + + // Token: 0x040000CF RID: 207 + public readonly VmInstrInfo Ldloc_s_ = new VmInstrInfo(1019004451, VmOperandType.Ot8Byte); + + // Token: 0x040000D0 RID: 208 + public readonly VmInstrInfo Conv_i2_ = new VmInstrInfo(-108178384, VmOperandType.Ot11Nope); + + // Token: 0x040000D1 RID: 209 + public readonly VmInstrInfo Conv_ovf_i_ = new VmInstrInfo(-2109763431, VmOperandType.Ot11Nope); + + // Token: 0x040000D2 RID: 210 + public readonly VmInstrInfo Ble_ = new VmInstrInfo(1321262543, VmOperandType.Ot0UInt); + + // Token: 0x040000D3 RID: 211 + public readonly VmInstrInfo Unbox_ = new VmInstrInfo(-1668682548, VmOperandType.Ot5Int); + + // Token: 0x040000D4 RID: 212 + public readonly VmInstrInfo Stelem_r4_ = new VmInstrInfo(-1251429380, VmOperandType.Ot11Nope); + + // Token: 0x040000D5 RID: 213 + public readonly VmInstrInfo Stloc_3_ = new VmInstrInfo(1073782561, VmOperandType.Ot11Nope); + + // Token: 0x040000D7 RID: 215 + public readonly VmInstrInfo Brtrue_ = new VmInstrInfo(1985375111, VmOperandType.Ot0UInt); + + // Token: 0x040000D8 RID: 216 + public readonly VmInstrInfo Stelem_ = new VmInstrInfo(-633052479, VmOperandType.Ot5Int); + + // Token: 0x040000D9 RID: 217 + public readonly VmInstrInfo Stelem_i4_ = new VmInstrInfo(-638226942, VmOperandType.Ot11Nope); + + // Token: 0x040000DA RID: 218 + public readonly VmInstrInfo Conv_ovf_u1_un_ = new VmInstrInfo(-854623375, VmOperandType.Ot11Nope); + + // Token: 0x040000DB RID: 219 + public readonly VmInstrInfo Add_ovf_un_ = new VmInstrInfo(-2145629048, VmOperandType.Ot11Nope); + + // Token: 0x040000DC RID: 220 + public readonly VmInstrInfo Conv_u8_ = new VmInstrInfo(1396092080, VmOperandType.Ot11Nope); + + // Token: 0x040000DE RID: 222 + public readonly VmInstrInfo Bgt_ = new VmInstrInfo(-939929863, VmOperandType.Ot0UInt); + + // Token: 0x040000E2 RID: 226 + public readonly VmInstrInfo Bgt_un_ = new VmInstrInfo(-73779400, VmOperandType.Ot0UInt); + + // Token: 0x040000E3 RID: 227 + public readonly VmInstrInfo Stelem_r8_ = new VmInstrInfo(849078739, VmOperandType.Ot11Nope); + + // Token: 0x040000E5 RID: 229 + public readonly VmInstrInfo Mkrefany_ = new VmInstrInfo(1810420701, VmOperandType.Ot5Int); + + // Token: 0x040000E6 RID: 230 + public readonly VmInstrInfo Conv_ovf_u_un_ = new VmInstrInfo(-1209242284, VmOperandType.Ot11Nope); + + // Token: 0x040000E7 RID: 231 + public readonly VmInstrInfo Conv_ovf_i1_ = new VmInstrInfo(-1678823314, VmOperandType.Ot11Nope); + + // Token: 0x040000E8 RID: 232 + public readonly VmInstrInfo Conv_ovf_i1_un_ = new VmInstrInfo(-1171707127, VmOperandType.Ot11Nope); + + // Token: 0x040000EA RID: 234 + public readonly VmInstrInfo Stsfld_ = new VmInstrInfo(-1272257470, VmOperandType.Ot5Int); + + // Token: 0x040000EB RID: 235 + public readonly VmInstrInfo Starg_ = new VmInstrInfo(-1559324355, VmOperandType.Ot1UShort); + + // Token: 0x040000EC RID: 236 + public readonly VmInstrInfo Ldflda_ = new VmInstrInfo(685223722, VmOperandType.Ot5Int); + + // Token: 0x040000EE RID: 238 + public readonly VmInstrInfo Sub_ = new VmInstrInfo(1925911547, VmOperandType.Ot11Nope); + + // Token: 0x040000F0 RID: 240 + public readonly VmInstrInfo Conv_ovf_i2_ = new VmInstrInfo(2079826493, VmOperandType.Ot11Nope); + + // Token: 0x040000F1 RID: 241 + public readonly VmInstrInfo Ldarg_0_ = new VmInstrInfo(-1817778622, VmOperandType.Ot11Nope); + + // Token: 0x040000F2 RID: 242 + public readonly VmInstrInfo Ldelem_i2_ = new VmInstrInfo(-1703864226, VmOperandType.Ot11Nope); + + // Token: 0x040000F3 RID: 243 + public readonly VmInstrInfo Ceq_ = new VmInstrInfo(-490385948, VmOperandType.Ot11Nope); + + // Token: 0x040000F4 RID: 244 + public readonly VmInstrInfo Ldelema_ = new VmInstrInfo(-659575843, VmOperandType.Ot5Int); + + // Token: 0x040000F5 RID: 245 + public readonly VmInstrInfo Localloc_ = new VmInstrInfo(487454996, VmOperandType.Ot11Nope); + + // Token: 0x040000F6 RID: 246 + public readonly VmInstrInfo Conv_ovf_i4_un_ = new VmInstrInfo(-900057353, VmOperandType.Ot11Nope); + + // Token: 0x040000F7 RID: 247 + public readonly VmInstrInfo Bge_un_ = new VmInstrInfo(784647969, VmOperandType.Ot0UInt); + + // Token: 0x040000F8 RID: 248 + public readonly VmInstrInfo Ldelem_ref_ = new VmInstrInfo(880972378, VmOperandType.Ot11Nope); + + // Token: 0x040000FA RID: 250 + public readonly VmInstrInfo Conv_ovf_i8_un_ = new VmInstrInfo(20637445, VmOperandType.Ot11Nope); + + // Token: 0x040000FB RID: 251 + public readonly VmInstrInfo Ldind_i8_ = new VmInstrInfo(-607543449, VmOperandType.Ot11Nope); + + // Token: 0x040000FC RID: 252 + public readonly VmInstrInfo Refanyval_ = new VmInstrInfo(1010177566, VmOperandType.Ot5Int); + + // Token: 0x040000FE RID: 254 + public readonly VmInstrInfo Dup_ = new VmInstrInfo(85722172, VmOperandType.Ot11Nope); + + // Token: 0x040000FF RID: 255 + public readonly VmInstrInfo Stloc_0_ = new VmInstrInfo(-1071153572, VmOperandType.Ot11Nope); + + // Token: 0x04000100 RID: 256 + public readonly VmInstrInfo Ldc_i4_4_ = new VmInstrInfo(-72363801, VmOperandType.Ot11Nope); + + // Token: 0x04000101 RID: 257 + public readonly VmInstrInfo Ldind_r8_ = new VmInstrInfo(813030660, VmOperandType.Ot11Nope); + + // Token: 0x04000102 RID: 258 + public readonly VmInstrInfo Ldc_i4_7_ = new VmInstrInfo(-1136876649, VmOperandType.Ot11Nope); + + // Token: 0x04000103 RID: 259 + public readonly VmInstrInfo Stelem_i8_ = new VmInstrInfo(588832478, VmOperandType.Ot11Nope); + + // Token: 0x04000105 RID: 261 + public readonly VmInstrInfo Mul_ovf_un_ = new VmInstrInfo(-356198078, VmOperandType.Ot11Nope); + + // Token: 0x04000106 RID: 262 + public readonly VmInstrInfo Conv_u_ = new VmInstrInfo(1795519976, VmOperandType.Ot11Nope); + + // Token: 0x04000108 RID: 264 + public readonly VmInstrInfo Ldelem_i_ = new VmInstrInfo(1499071663, VmOperandType.Ot11Nope); + + // Token: 0x04000109 RID: 265 + public readonly VmInstrInfo Ldarg_ = new VmInstrInfo(-1071239412, VmOperandType.Ot1UShort); + + // Token: 0x0400010A RID: 266 + public readonly VmInstrInfo Conv_r_un_ = new VmInstrInfo(-23925463, VmOperandType.Ot11Nope); + + // Token: 0x0400010B RID: 267 + public readonly VmInstrInfo Ldc_i4_8_ = new VmInstrInfo(1119515810, VmOperandType.Ot11Nope); + + // Token: 0x0400010C RID: 268 + public readonly VmInstrInfo Conv_i8_ = new VmInstrInfo(1980167243, VmOperandType.Ot11Nope); + + // Token: 0x0400010D RID: 269 + public readonly VmInstrInfo Ldloc_1_ = new VmInstrInfo(704985473, VmOperandType.Ot11Nope); + + // Token: 0x0400010E RID: 270 + public readonly VmInstrInfo Ldelem_u2_ = new VmInstrInfo(-1142530894, VmOperandType.Ot11Nope); + + // Token: 0x0400010F RID: 271 + public readonly VmInstrInfo Throw_ = new VmInstrInfo(-958454075, VmOperandType.Ot11Nope); + + // Token: 0x04000110 RID: 272 + public readonly VmInstrInfo Cpblk_ = new VmInstrInfo(-123910492, VmOperandType.Ot11Nope); + + // Token: 0x04000111 RID: 273 + public readonly VmInstrInfo Ldind_u1_ = new VmInstrInfo(1476085916, VmOperandType.Ot11Nope); + + // Token: 0x04000113 RID: 275 + public readonly VmInstrInfo Stloc_2_ = new VmInstrInfo(392938325, VmOperandType.Ot11Nope); + + // Token: 0x04000114 RID: 276 + public readonly VmInstrInfo Ldarg_3_ = new VmInstrInfo(-1756998893, VmOperandType.Ot11Nope); + + // Token: 0x04000115 RID: 277 + public readonly VmInstrInfo Stloc_ = new VmInstrInfo(1447397361, VmOperandType.Ot1UShort); + + // Token: 0x04000117 RID: 279 + public readonly VmInstrInfo Ldc_i4_5_ = new VmInstrInfo(-656328799, VmOperandType.Ot11Nope); + + // Token: 0x04000118 RID: 280 + public readonly VmInstrInfo Conv_ovf_u1_ = new VmInstrInfo(344575979, VmOperandType.Ot11Nope); + + // Token: 0x0400011A RID: 282 + public readonly VmInstrInfo Ldind_i4_ = new VmInstrInfo(234126039, VmOperandType.Ot11Nope); + + // Token: 0x0400011B RID: 283 + public readonly VmInstrInfo Switch_ = new VmInstrInfo(8625656, VmOperandType.Ot9IntArr); + + // Token: 0x0400011C RID: 284 + public readonly VmInstrInfo Arglist_ = new VmInstrInfo(1783361912, VmOperandType.Ot11Nope); + + // Token: 0x0400011F RID: 287 + public readonly VmInstrInfo Shr_un_ = new VmInstrInfo(897680915, VmOperandType.Ot11Nope); + + // Token: 0x04000120 RID: 288 + public readonly VmInstrInfo Ldloc_2_ = new VmInstrInfo(-17993965, VmOperandType.Ot11Nope); + + // Token: 0x04000121 RID: 289 + public readonly VmInstrInfo Conv_ovf_u4_ = new VmInstrInfo(1596489702, VmOperandType.Ot11Nope); + + // Token: 0x04000122 RID: 290 + public readonly VmInstrInfo Bge_ = new VmInstrInfo(-1225693454, VmOperandType.Ot0UInt); + + // Token: 0x04000123 RID: 291 + public readonly VmInstrInfo Ldloc_0_ = new VmInstrInfo(1021709264, VmOperandType.Ot11Nope); + + // Token: 0x04000124 RID: 292 + public readonly VmInstrInfo Bne_un_ = new VmInstrInfo(68951288, VmOperandType.Ot0UInt); + + // Token: 0x04000126 RID: 294 + public readonly VmInstrInfo Stelem_i2_ = new VmInstrInfo(1223054294, VmOperandType.Ot11Nope); + + // Token: 0x04000127 RID: 295 + public readonly VmInstrInfo Sub_ovf_un_ = new VmInstrInfo(-851734976, VmOperandType.Ot11Nope); + + // Token: 0x04000128 RID: 296 + public readonly VmInstrInfo Ret_ = new VmInstrInfo(1882847521, VmOperandType.Ot11Nope); + #endregion + } + + public enum VmOperandType + { + Ot0UInt, Ot1UShort, Ot2Byte, Ot3UShort, Ot4Double, Ot5Int, Ot6SByte, Ot7Long, Ot8Byte, Ot9IntArr, Ot10Float, Ot11Nope, Ot12Int + } + // Token: 0x0200005F RID: 95 + public class VmInstrInfo // \u000F\u2005 + { + // Token: 0x06000377 RID: 887 RVA: 0x00015B74 File Offset: 0x00013D74 + public VmInstrInfo(int id, VmOperandType operandType) + { + Id = id; + OperandType = operandType; + } + + // Token: 0x06000378 RID: 888 RVA: 0x00015B8C File Offset: 0x00013D8C + // Token: 0x06000379 RID: 889 RVA: 0x00015B94 File Offset: 0x00013D94 + // Token: 0x0400018F RID: 399 + public int Id { get; } + + // Token: 0x0600037A RID: 890 RVA: 0x00015BA0 File Offset: 0x00013DA0 + // Token: 0x04000190 RID: 400 + public VmOperandType OperandType { get; } + + // Token: 0x0600037B RID: 891 RVA: 0x00015BA8 File Offset: 0x00013DA8 + public override bool Equals(object o) + { + var p = o as VmInstrInfo; + return (p != null) && EqualTo(p); + } + + // Token: 0x0600037C RID: 892 RVA: 0x00015BD0 File Offset: 0x00013DD0 + private bool EqualTo(VmInstrInfo p) + { + return p.Id== Id; + } + + // Token: 0x0600037D RID: 893 RVA: 0x00015BE0 File Offset: 0x00013DE0 + public static bool operator ==(VmInstrInfo o1, VmInstrInfo o2) + { + // ReSharper disable once PossibleNullReferenceException + return o1.EqualTo(o2); + } + + // Token: 0x0600037E RID: 894 RVA: 0x00015BEC File Offset: 0x00013DEC + public static bool operator !=(VmInstrInfo o1, VmInstrInfo o2) + { + return !(o1 == o2); + } + + // Token: 0x0600037F RID: 895 RVA: 0x00015BF8 File Offset: 0x00013DF8 + public override int GetHashCode() + { + return Id.GetHashCode(); + } + + // Token: 0x06000380 RID: 896 RVA: 0x00015C14 File Offset: 0x00013E14 + public override string ToString() + { + return Id.ToString(); + } + } +} diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VmMethodHeader.cs b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VmMethodHeader.cs new file mode 100644 index 0000000..0d4a0ab --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VmMethodHeader.cs @@ -0,0 +1,42 @@ +namespace UnitTestProject.RefVm +{ + // Token: 0x02000028 RID: 40 + public sealed class VmMethodHeader // \u0006 + { + // Token: 0x06000120 RID: 288 RVA: 0x00005F08 File Offset: 0x00004108 + // Token: 0x06000121 RID: 289 RVA: 0x00005F10 File Offset: 0x00004110 + // Token: 0x04000047 RID: 71 + public LocalVarType[] LocalVarTypes /* \u0003 */ { get; set; } + + // Token: 0x06000122 RID: 290 RVA: 0x00005F1C File Offset: 0x0000411C + // Token: 0x06000123 RID: 291 RVA: 0x00005F24 File Offset: 0x00004124 + // Token: 0x0400004B RID: 75 + public ArgTypeToOutput[] ArgsTypeToOutput /* \u000E */ { get; set; } + + // Token: 0x06000124 RID: 292 RVA: 0x00005F30 File Offset: 0x00004130 + // Token: 0x06000125 RID: 293 RVA: 0x00005F38 File Offset: 0x00004138 + // Token: 0x04000048 RID: 72 + public string Name /* \u0002 */ { get; set; } + + // Token: 0x06000126 RID: 294 RVA: 0x00005F44 File Offset: 0x00004144 + // Token: 0x06000127 RID: 295 RVA: 0x00005F4C File Offset: 0x0000414C + // Token: 0x04000046 RID: 70 + public int ClassId /* \u0002 */ { get; set; } + + // Token: 0x06000128 RID: 296 RVA: 0x00005F58 File Offset: 0x00004158 + // Token: 0x06000129 RID: 297 RVA: 0x00005F60 File Offset: 0x00004160 + // Token: 0x04000049 RID: 73 + public int ReturnTypeId /* \u0008 */ { get; set; } + + // Token: 0x0600012A RID: 298 RVA: 0x00005F6C File Offset: 0x0000416C + // Token: 0x0600012B RID: 299 RVA: 0x00005F74 File Offset: 0x00004174 + // Token: 0x0400004A RID: 74 + public byte Flags /* \u0006 */ { private get; set; } + + // Token: 0x0600012C RID: 300 RVA: 0x00005F80 File Offset: 0x00004180 + public bool IsStatic() // \u0002 + { + return (Flags & 2) > 0; + } + } +} diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VmPosParser.cs b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VmPosParser.cs new file mode 100644 index 0000000..7b3fb2a --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VmPosParser.cs @@ -0,0 +1,96 @@ +using System; +using System.IO; + +namespace UnitTestProject.RefVm +{ + internal static class VmPosParser // \u0006\u2006 + { + // Token: 0x0600016A RID: 362 RVA: 0x00007810 File Offset: 0x00005A10 + public static byte[] Parse(string pos) // dest + { + if (pos == null) + { + throw new Exception(); + } + var memoryStream = new MemoryStream(pos.Length * 4 / 5); + byte[] result; + using(memoryStream) + { + var cnt = 0; + var val = 0u; + foreach (var c in pos) + { + if (c == 'z' && cnt == 0) + { + WriteDwPart(memoryStream, val, 0); + } + else + { + if (c< '!' || c> 'u') + { + throw new Exception(); + } + checked + { + val += (uint)(Arr[cnt] * (ulong)checked(c - '!')); + } + cnt++; + if (cnt == 5) + { + WriteDwPart(memoryStream, val, 0); + cnt = 0; + val = 0u; + } + } + } + if (cnt == 1) + { + throw new Exception(); + } + if (cnt > 1) + { + for (var j = cnt; j < 5; j++) + { + checked + { + val += 84u * Arr[j]; + } + } + WriteDwPart(memoryStream, val, 5 - cnt); + } + result = memoryStream.ToArray(); + } + return result; + } + + // Token: 0x0600016B RID: 363 RVA: 0x00007900 File Offset: 0x00005B00 + private static void WriteDwPart(Stream dest, uint val, int ignoreLow) // dest + { + dest.WriteByte((byte)(val >> 24)); + if (ignoreLow == 3) + { + return; + } + dest.WriteByte((byte)(val >> 16 & 255u)); + if (ignoreLow == 2) + { + return; + } + dest.WriteByte((byte)(val >> 8 & 255u)); + if (ignoreLow == 1) + { + return; + } + dest.WriteByte((byte)(val & 255u)); + } + + // Token: 0x04000131 RID: 305 + private static readonly uint[] Arr = { + 52200625u, + 614125u, + 7225u, + 85u, + 1u + }; + } +} diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VmStreamWrapper.cs b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VmStreamWrapper.cs new file mode 100644 index 0000000..8da27f8 --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VmStreamWrapper.cs @@ -0,0 +1,116 @@ +using System; +using System.IO; + +namespace UnitTestProject.RefVm +{ + // Token: 0x02000021 RID: 33 + public sealed class VmStreamWrapper : Stream // \u0005\u2005 + { + // Token: 0x060000CB RID: 203 RVA: 0x00004A20 File Offset: 0x00002C20 + public VmStreamWrapper(Stream src, int xorKey) + { + SetStream(src); + _xorKey = xorKey; + } + + // Token: 0x060000CC RID: 204 RVA: 0x00004A38 File Offset: 0x00002C38 + public Stream GetStream() // \u0008\u2003\u2003\u2001\u2001\u2000\u2000\u2008\u2000\u2001\u2000\u2008\u200A\u2008\u200B\u2003\u200B + { + return _srcStream; + } + + // Token: 0x060000CD RID: 205 RVA: 0x00004A40 File Offset: 0x00002C40 + private void SetStream(Stream src) // \u0002 + { + _srcStream = src; + } + + // Token: 0x17000001 RID: 1 + // (get) Token: 0x060000CE RID: 206 RVA: 0x00004A4C File Offset: 0x00002C4C + public override bool CanRead => GetStream().CanRead; + + // Token: 0x17000002 RID: 2 + // (get) Token: 0x060000CF RID: 207 RVA: 0x00004A5C File Offset: 0x00002C5C + public override bool CanSeek => GetStream().CanSeek; + + // Token: 0x17000003 RID: 3 + // (get) Token: 0x060000D0 RID: 208 RVA: 0x00004A6C File Offset: 0x00002C6C + public override bool CanWrite => GetStream().CanWrite; + + // Token: 0x060000D1 RID: 209 RVA: 0x00004A7C File Offset: 0x00002C7C + public override void Flush() + { + GetStream().Flush(); + } + + // Token: 0x17000004 RID: 4 + // (get) Token: 0x060000D2 RID: 210 RVA: 0x00004A8C File Offset: 0x00002C8C + public override long Length => GetStream().Length; + + // Token: 0x17000005 RID: 5 + // (get) Token: 0x060000D3 RID: 211 RVA: 0x00004A9C File Offset: 0x00002C9C + // (set) Token: 0x060000D4 RID: 212 RVA: 0x00004AAC File Offset: 0x00002CAC + public override long Position + { + get + { + return GetStream().Position; + } + set + { + GetStream().Position = value; + } + } + + // Token: 0x060000D5 RID: 213 RVA: 0x00004ABC File Offset: 0x00002CBC + private byte Xor(byte data, long key2) // \u0002 + { + var b = (byte)(_xorKey ^ -559030707 ^ (int)((uint)key2)); + return (byte)(data ^ b); + } + + // Token: 0x060000D6 RID: 214 RVA: 0x00004AE0 File Offset: 0x00002CE0 + public override void Write(byte[] data, int offset, int size) + { + var array = new byte[size]; + Buffer.BlockCopy(data, offset, array, 0, size); + var position = Position; + for (var i = 0; i < size; i++) + { + array[i] = Xor(array[i], position + i); + } + GetStream().Write(array, 0, size); + } + + // Token: 0x060000D7 RID: 215 RVA: 0x00004B30 File Offset: 0x00002D30 + public override int Read(byte[] data, int offset, int size) + { + var position = Position; + var array = new byte[size]; + var num = GetStream().Read(array, 0, size); + for (var i = 0; i < num; i++) + { + data[i + offset] = Xor(array[i], position + i); + } + return num; + } + + // Token: 0x060000D8 RID: 216 RVA: 0x00004B7C File Offset: 0x00002D7C + public override long Seek(long pos, SeekOrigin from) + { + return GetStream().Seek(pos, from); + } + + // Token: 0x060000D9 RID: 217 RVA: 0x00004B8C File Offset: 0x00002D8C + public override void SetLength(long val) + { + GetStream().SetLength(val); + } + + // Token: 0x0400002A RID: 42 + private readonly int _xorKey; // \u0002 + + // Token: 0x0400002B RID: 43 + private Stream _srcStream; // \u0003 + } +} diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/UnitTest1.cs b/runtime/VMProtect.Runtime/Tests/UnitTestProject/UnitTest1.cs new file mode 100644 index 0000000..ea67e80 --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/UnitTest1.cs @@ -0,0 +1,110 @@ +using System; +using System.Net; +using System.Text; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using VMProtect; + +namespace UnitTestProject +{ + [TestClass] + public class UnitTest1 + { + [TestMethod] + // ReSharper disable once InconsistentNaming + public void TestRC5() + { + var key = CipherRC5.CreateRandomKey(); + var rc5 = new CipherRC5(key); + + var dataStr = "Тестовые данные для TestRC5"; + var dataBytes = Encoding.UTF8.GetBytes(dataStr); + Array.Resize(ref dataBytes, (dataBytes.Length + 7)/8*8); + + var encodedBytes = rc5.Encrypt(dataBytes); + var dataBytes2 = rc5.Decrypt(encodedBytes); + + CollectionAssert.AreNotEqual(dataBytes, encodedBytes); + CollectionAssert.AreEqual(dataBytes, dataBytes2); + } + + [TestMethod] + public void TestHwid() + { + var hwid = new HardwareID(); + Assert.AreNotSame(0, hwid.ToString().Length); + var machine = Dns.GetHostName().ToUpperInvariant(); + var txtHwid = hwid.ToString(); + if (machine == "ACER-V3") + Assert.AreEqual("2D3kAD28P7M7soVoCjyOUA==", txtHwid); + else if (machine == "WORK") + Assert.AreEqual("AIUkDL3k4HTLFrVrPmOIpw==", txtHwid); + else if (machine == "BUILD7N1") + Assert.AreEqual("HBG8w5UkOMh714KeZow8vg==", txtHwid); + else + Assert.Fail("Append branch for machine '{0}' with result '{1}'", machine, txtHwid); + } + + [TestMethod] + public void TestHwidCompare() + { + var hwid = new HardwareID(); + var cur = hwid.GetBytes(); + var test = new byte[cur.Length]; + + Array.Copy(cur, test, cur.Length); + // change one id + for (var i = 0; i < cur.Length; i += 4) + { + test[i] = cur[i]; + switch (test[i] & 3) { + case 3: + test[i] ^= 4; + break; + } + } + Assert.IsTrue(hwid.IsCorrect(test)); + + + // change two ids + Array.Copy(cur, test, cur.Length); + for (var i = 0; i < cur.Length; i += 4) + { + switch (test[i] & 3) + { + case 2: + case 3: + test[i] ^= 4; + break; + } + } + Assert.IsFalse(hwid.IsCorrect(test)); + + // change three ids + Array.Copy(cur, test, cur.Length); + for (var i = 0; i < cur.Length; i += 4) + { + switch (test[i] & 3) + { + case 2: + case 3: + test[i] ^= 4; + break; + } + } + Assert.IsFalse(hwid.IsCorrect(test)); + + // change cpu`s id + Array.Copy(cur, test, cur.Length); + for (var i = 0; i < cur.Length; i += 4) + { + switch (test[i] & 3) + { + case 0: + test[i] ^= 4; + break; + } + } + Assert.IsFalse(hwid.IsCorrect(test)); + } + } +} diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/UnitTestCombine.cs b/runtime/VMProtect.Runtime/Tests/UnitTestProject/UnitTestCombine.cs new file mode 100644 index 0000000..fb1a6db --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/UnitTestCombine.cs @@ -0,0 +1,1715 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Reflection; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Reflection.Emit; +using System.Runtime.InteropServices; +using UnitTestProject.RefVm; +using VMProtect; +using OpCodes = System.Reflection.Emit.OpCodes; + +namespace UnitTestProject +{ + [TestClass] + public class UnitTestCombine + { + // шаблон для окружающего кода для некой инструкции + public enum CodeTemplate + { + BranchTwoOpBool, // 2 операнда на стеке, 2 ветки исполнения (одна возвращает true, другая false) + SingleOpAny, // 1 операнд на стеке, инструкция, возвращающая разные типы + TwoOpBool, // 2 операнда на стеке, инструкция, возвращающая bool + TwoOpAny, // 2 операнда на стеке, инструкция, возвращающая разные типы + } + + [TestMethod] + public void TestMethodRefVm() + { + InitStrings(); + TestMethod(new MsilToVmTestCompilerRefVm()); + } + + [TestMethod] + public void TestMethodVmp() + { + TestMethod(new MsilToVmTestCompilerVmp()); + } + + [SuppressMessage("ReSharper", "RedundantCast")] + public void TestMethod(MsilToVmTestCompiler c) + { + // типовые и крайние значения следующих типов: + // SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, + // float, double, + // LongEnum, ULongEnum, Char, SByteEnum, ByteEnum, ShortEnum, UShortEnum, IntEnum, UIntEnum + // bool, object, IntPtr, UIntPtr + //TODO: decimal + #region valsVector + // ReSharper disable once RedundantExplicitArrayCreation + var valsVector = new object [] + { + (SByte)0, (SByte)1, (SByte)(-1), SByte.MaxValue, SByte.MinValue, (SByte)0x55, // SByte + (Byte)0, (Byte)1, Byte.MaxValue, (Byte)0xAA, // Byte + (Int16)0, (Int16)1, (Int16)(-1), Int16.MaxValue, Int16.MinValue, (Int16)0x55AA, // Int16 + (UInt16)0, (UInt16)1, UInt16.MaxValue, (UInt16)0xAA55, // UInt16 + 0, 1, -1, Int32.MaxValue, Int32.MinValue, 0x55AA55AA, // Int32 + (UInt32)0, (UInt32)1, UInt32.MaxValue, 0xAA5555AA, // UInt32 + (Int64)0, (Int64)1, (Int64)(-1), Int64.MaxValue, Int64.MinValue, 0x55AA55AA55AA55AA, // Int64 + (UInt64)0, (UInt64)1, UInt64.MaxValue, 0xAA5555AAAA5555AA, // UInt64 + (float)0, (float)1, (float)(-1), float.MaxValue, float.MinValue, float.Epsilon, float.NaN, + float.NegativeInfinity, float.PositiveInfinity, (float)(5678.1234),(float)(1234.5678), (float)(-5678.1234), (float)(-1234.5678), + (float)(2147483647.0 * 3.0), (float)(-2147483647.0 * 3.0), (float)(9223372336854775807.0 * 3.0), -(float)(9223372336854775807.0 * 3.0), // float + (double)0, (double)1, (double)(-1), double.MaxValue, double.MinValue, double.Epsilon, double.NaN, + double.NegativeInfinity, double.PositiveInfinity, 5678.1234, 1234.5678, -5678.1234, -1234.5678, + (double)(2147483647.0 * 3.0), (double)(-2147483647.0 * 3.0), (double)9223372336854775807.0 * 3.0, -(double)9223372336854775807.0 * 3.0, // double + (MsilToVmTestCompiler.LongEnum)0, (MsilToVmTestCompiler.LongEnum)1, (MsilToVmTestCompiler.LongEnum)(-1), (MsilToVmTestCompiler.LongEnum)Int64.MaxValue, (MsilToVmTestCompiler.LongEnum)Int64.MinValue, (MsilToVmTestCompiler.LongEnum)0x55AA55AA55AA55AA, // LongEnum + (MsilToVmTestCompiler.ULongEnum)0, (MsilToVmTestCompiler.ULongEnum)1, (MsilToVmTestCompiler.ULongEnum)UInt64.MaxValue, (MsilToVmTestCompiler.ULongEnum)0xAA5555AAAA5555AA, // ULongEnum + (Char)0, (Char)1, 'Ю', Char.MaxValue, (Char)0xAA55, // Char + (MsilToVmTestCompiler.SByteEnum)0, (MsilToVmTestCompiler.SByteEnum)1, (MsilToVmTestCompiler.SByteEnum)(-1), (MsilToVmTestCompiler.SByteEnum)sbyte.MaxValue, (MsilToVmTestCompiler.SByteEnum)sbyte.MinValue, (MsilToVmTestCompiler.SByteEnum)0x55, // SByteEnum + (MsilToVmTestCompiler.ByteEnum)0, (MsilToVmTestCompiler.ByteEnum)1, (MsilToVmTestCompiler.ByteEnum)Byte.MaxValue, (MsilToVmTestCompiler.ByteEnum)0xAA, // ByteEnum + (MsilToVmTestCompiler.ShortEnum)0, (MsilToVmTestCompiler.ShortEnum)1, (MsilToVmTestCompiler.ShortEnum)(-1), (MsilToVmTestCompiler.ShortEnum)short.MaxValue, (MsilToVmTestCompiler.ShortEnum)short.MinValue, (MsilToVmTestCompiler.ShortEnum)0x55AA, // ShortEnum + (MsilToVmTestCompiler.UShortEnum)0, (MsilToVmTestCompiler.UShortEnum)1, (MsilToVmTestCompiler.UShortEnum)ushort.MaxValue, (MsilToVmTestCompiler.UShortEnum)0xAA55, // UShortEnum + (MsilToVmTestCompiler.IntEnum)0, (MsilToVmTestCompiler.IntEnum)1, (MsilToVmTestCompiler.IntEnum)(-1), (MsilToVmTestCompiler.IntEnum)int.MaxValue, (MsilToVmTestCompiler.IntEnum)int.MinValue, (MsilToVmTestCompiler.IntEnum)0x55AA55AA, // IntEnum + (MsilToVmTestCompiler.UIntEnum)0, (MsilToVmTestCompiler.UIntEnum)1, (MsilToVmTestCompiler.UIntEnum)uint.MaxValue, (MsilToVmTestCompiler.UIntEnum)0xAA5555AA, // UIntEnum + true, false, // bool + new object(), //object + new IntPtr(0), new UIntPtr(0), // IntPtr, UIntPtr + }; +#endregion + var errCounters = new int[(int)MsilToVmTestCompiler.InvokeTestCombineError.Cnt]; + var operations = new List<KeyValuePair<OpCode, CodeTemplate>> + { + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Add, CodeTemplate.TwoOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Add_Ovf, CodeTemplate.TwoOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Add_Ovf_Un, CodeTemplate.TwoOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.And, CodeTemplate.TwoOpAny), + //Arglist не годится для этого теста + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Beq_S, CodeTemplate.BranchTwoOpBool), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Bge_S, CodeTemplate.BranchTwoOpBool), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Bge_Un_S, CodeTemplate.BranchTwoOpBool), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Bgt_S, CodeTemplate.BranchTwoOpBool), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Bgt_Un_S, CodeTemplate.BranchTwoOpBool), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Ble_S, CodeTemplate.BranchTwoOpBool), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Ble_Un_S, CodeTemplate.BranchTwoOpBool), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Blt_S, CodeTemplate.BranchTwoOpBool), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Blt_Un_S, CodeTemplate.BranchTwoOpBool), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Bne_Un_S, CodeTemplate.BranchTwoOpBool), + //TODO Box + //Br_S тестируется неявно в этом тесте + //Break не годится для этого теста + //TODO Brfalse_S + //TODO Brtrue_S + //Call тестируется в TestNewobj + //Calli Callvirt Castclass не годятся для этого теста + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Ceq, CodeTemplate.TwoOpBool), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Cgt, CodeTemplate.TwoOpBool), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Cgt_Un, CodeTemplate.TwoOpBool), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Ckfinite, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Clt, CodeTemplate.TwoOpBool), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Clt_Un, CodeTemplate.TwoOpBool), + //Constrained не годится для этого теста + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_I, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_I1, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_I2, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_I4, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_I8, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_Ovf_I, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_Ovf_I1, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_Ovf_I1_Un, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_Ovf_I2, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_Ovf_I2_Un, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_Ovf_I4, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_Ovf_I4_Un, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_Ovf_I8, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_Ovf_I8_Un, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_Ovf_I_Un, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_Ovf_U, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_Ovf_U1, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_Ovf_U1_Un, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_Ovf_U2, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_Ovf_U2_Un, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_Ovf_U4, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_Ovf_U4_Un, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_Ovf_U8, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_Ovf_U8_Un, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_Ovf_U_Un, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_R4, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_R8, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_R_Un, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_U, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_U1, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_U2, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_U4, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_U8, CodeTemplate.SingleOpAny), + //Cpblk Cpobj не годятся для этого теста + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Div, CodeTemplate.TwoOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Div_Un, CodeTemplate.TwoOpAny), + //TODO: Dup + //Endfilter Endfinally Initblk Initobj Isinst Jmp Ldarg не годятся для этого теста + //Ldarg_0 тестируется неявно в этом тесте + //Ldarg_1 тестируется неявно в этом тесте + //Ldarg_2 Ldarg_3 Ldarg_S Ldarga не годятся для этого теста + //Ldarga_S тестируется в TestNewobj + //Ldc_I4 не годится для этого теста + //Ldc_I4_0 тестируется неявно в этом тесте + //Ldc_I4_1 тестируется неявно в этом тесте + //Ldc_I4_2 Ldc_I4_3 Ldc_I4_4 Ldc_I4_5 Ldc_I4_6 Ldc_I4_7 Ldc_I4_8 Ldc_I4_M1 Ldc_I4_S Ldc_I8 Ldc_R4 Ldc_R8 не годятся для этого теста + //Ldelem* Ldfld Ldflda Ldftn Ldind_* Ldlen Ldloc* Ldnull Ldobj Ldsfld Ldsflda Ldstr Ldtoken Ldvirtftn Leave Leave_S Localloc Mkrefany не годятся для этого теста + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Mul, CodeTemplate.TwoOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Mul_Ovf, CodeTemplate.TwoOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Mul_Ovf_Un, CodeTemplate.TwoOpAny), + //TODO new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Neg, CodeTemplate.SingleOp), + //Newarr не годится для этого теста + //Newobj тестируется в TestNewobj + //Nop не годится для этого теста + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Not, CodeTemplate.SingleOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Or, CodeTemplate.TwoOpAny), + //Pop Prefix* Readonly Refanytype Refanyval не годятся для этого теста + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Rem, CodeTemplate.TwoOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Rem_Un, CodeTemplate.TwoOpAny), + //Ret тестируется неявно в этом тесте + //Rethrow не годится для этого теста + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Shl, CodeTemplate.TwoOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Shr, CodeTemplate.TwoOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Shr_Un, CodeTemplate.TwoOpAny), + //Sizeof + //St* не годятся для этого теста + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Sub, CodeTemplate.TwoOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Sub_Ovf, CodeTemplate.TwoOpAny), + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Sub_Ovf_Un, CodeTemplate.TwoOpAny), + //Switch Tailcall Throw Unaligned + //TODO Unbox + //TODO Unbox_Any + //Volatile не годится для этого теста + new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Xor, CodeTemplate.TwoOpAny), + }; + foreach (var op in operations) + { + switch (op.Value) + { + case CodeTemplate.BranchTwoOpBool: + case CodeTemplate.TwoOpBool: + case CodeTemplate.TwoOpAny: + TestOperationTwoOp(c, op, valsVector, errCounters); + break; + case CodeTemplate.SingleOpAny: + TestOperationSingleOp(c, op, valsVector, errCounters); + break; + default: + Assert.Fail("Unsupported op.Value: {0}", op.Value); + break; + } + } + Console.Error.WriteLine("--- {0} results ---", IntPtr.Size == 4 ? "x86" : "x64"); + var sum = 0; + for (var i = 0; i < errCounters.Length; i++) + { + Console.Error.WriteLine("{0}: {1}", (MsilToVmTestCompiler.InvokeTestCombineError)i, errCounters[i]); + sum += errCounters[i]; + } + Console.Error.WriteLine("--- TOTAL: {0} ---", sum); + Assert.AreEqual(sum, errCounters[(int)MsilToVmTestCompiler.InvokeTestCombineError.NoError] + + errCounters[(int)MsilToVmTestCompiler.InvokeTestCombineError.NoErrorByStdEx]); + Console.Error.WriteLine(sum == errCounters[(int) MsilToVmTestCompiler.InvokeTestCombineError.NoError] + + errCounters[(int) MsilToVmTestCompiler.InvokeTestCombineError.NoErrorByStdEx] + ? "TEST PASSED" + : "TEST FAILED"); + } + + private void TestOperationTwoOp(MsilToVmTestCompiler c, KeyValuePair<OpCode, CodeTemplate> op, object[] valsVector, int[] errCounters) + { + foreach (var i in valsVector) + { + foreach (var j in valsVector) + { + object[] parameters = {i, j}; + string err, istr = i.ToString(), jstr = j.ToString(); + if (i is Char) + istr = $@"'\{Convert.ToInt32(i)}'"; + if (j is Char) + jstr = $@"'\{Convert.ToInt32(j)}'"; + + var res = TestOperation(c, op, parameters, errCounters, out err); + if(res > MsilToVmTestCompiler.InvokeTestCombineError.NoErrorByStdEx) + Console.Error.WriteLine("{0}.{1}(({4}){2}, ({5}){3}) = {6}", op.Key, op.Value, + istr, jstr, i.GetType().FullName, j.GetType().FullName, err); + } + } + } + + private void TestOperationSingleOp(MsilToVmTestCompiler c, KeyValuePair<OpCode, CodeTemplate> op, object[] valsVector, int[] errCounters) + { + foreach (object i in valsVector) + { + object[] parameters = { i }; + string err, istr = i.ToString(); + if (i is Char) + istr = $@"'\{Convert.ToInt32(i)}'"; + var res = TestOperation(c, op, parameters, errCounters, out err); + if (res > MsilToVmTestCompiler.InvokeTestCombineError.NoErrorByStdEx) + Console.Error.WriteLine("{0}.{1}(({3}){2}) = {4}", op.Key, op.Value, istr, i.GetType().FullName, err); + } + } + + [TestMethod] + public void TempRefVm() + { + InitStrings(); + var errCounters = new int[(int)MsilToVmTestCompiler.InvokeTestCombineError.Cnt]; + string err; + TestOperation(new MsilToVmTestCompilerRefVm(), new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Add_Ovf_Un, CodeTemplate.TwoOpAny), + // ReSharper disable once RedundantExplicitArrayCreation + new object[] { new object(), (System.SByte)0 }, errCounters, out err); + Assert.AreEqual(1, errCounters[0] + errCounters[1]); + } + + [TestMethod] + public void TempVmp() + { + var errCounters = new int[(int)MsilToVmTestCompiler.InvokeTestCombineError.Cnt]; + string err; + TestOperation(new MsilToVmTestCompilerVmp(), new KeyValuePair<OpCode, CodeTemplate>(OpCodes.Conv_U4, CodeTemplate.SingleOpAny), + // ReSharper disable once RedundantCast + new object[] { (Int32)0 }, errCounters, out err); + Console.WriteLine(err); + Assert.AreEqual(1, errCounters[0] + errCounters[1]); + } + + private static void InitStrings() + { + StringDecryptor.SetString(-1550347095, "The value is not finite real number."); + } + + private MsilToVmTestCompiler.InvokeTestCombineError TestOperation( + MsilToVmTestCompiler c, KeyValuePair<OpCode, CodeTemplate> op, object[] parameters, int [] errCounters, out string err) + { + DynamicMethod dyn; + err = ""; + var types = parameters.Select(o => o.GetType()).ToArray(); + switch (op.Value) + { + case CodeTemplate.BranchTwoOpBool: + dyn = DynBranch2Op(op, types); + break; + case CodeTemplate.SingleOpAny: + dyn = DynSingleOpAny(op, types); + break; + case CodeTemplate.TwoOpBool: + dyn = Dyn2OpBool(op, types); + break; + case CodeTemplate.TwoOpAny: + dyn = Dyn2OpAny(op, types); + break; + default: + Assert.Fail("Unsupported op.Value: {0}", op.Value); + // ReSharper disable once HeuristicUnreachableCode + return MsilToVmTestCompiler.InvokeTestCombineError.Cnt; + } + object dynRet, vmRet; + var ret = c.InvokeTestCombine(dyn, parameters, out dynRet, out vmRet, out err); + // TODO: для регрессии надо как-то научиться закладывать сюда все правильные результаты + if (errCounters != null) + { + if (ret > MsilToVmTestCompiler.InvokeTestCombineError.NoErrorByStdEx && + ExtendedEcma335.Check(op, parameters, vmRet)) + { + ret = MsilToVmTestCompiler.InvokeTestCombineError.NoErrorByStdEx; + } + + errCounters[(int)ret]++; + } + return ret; + } + + private DynamicMethod DynSingleOpAny(KeyValuePair<OpCode, CodeTemplate> op, Type[] types) + { + Type pushedT; + switch (op.Key.StackBehaviourPush) + { + default: + Assert.Fail("DynSingleOp unsupported StackBehaviourPush={0}", op.Key.StackBehaviourPush); + // ReSharper disable once HeuristicUnreachableCode + return null; + case StackBehaviour.Pushi: + pushedT = typeof(Int32); + break; + case StackBehaviour.Pushi8: + pushedT = typeof(Int64); + break; + case StackBehaviour.Pushr4: + pushedT = typeof(float); + break; + case StackBehaviour.Pushr8: + pushedT = typeof(double); + break; + case StackBehaviour.Push1: + pushedT = CompatibleType(types[0], types[0], false); + if (pushedT == typeof(object)) pushedT = typeof(IntPtr); + break; + } + if ((IntPtr.Size == 8) && (op.Key.Equals(OpCodes.Conv_I) || op.Key.Equals(OpCodes.Conv_Ovf_I) || op.Key.Equals(OpCodes.Conv_Ovf_I_Un))) + pushedT = typeof(Int64); + if (op.Key.Equals(OpCodes.Conv_U) ||op.Key.Equals(OpCodes.Conv_Ovf_U) || op.Key.Equals(OpCodes.Conv_Ovf_U_Un)) + pushedT = (IntPtr.Size == 8) ? typeof(UInt64) : typeof(UInt32); + var dyn = new DynamicMethod(op.Key.Name, pushedT, types, typeof(void), true); + var gen = dyn.GetILGenerator(); + + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(op.Key); + gen.Emit(OpCodes.Ret); + + return dyn; + } + + internal class ClassNewobj + { + public const long Check = 0xF00D; + public long Ptr; + public unsafe ClassNewobj(byte *ptr) + { + Ptr = (long) ptr; + } + } + public static unsafe object StatNewobj(IntPtr ptr) + { + return new ClassNewobj((byte *)ptr.ToPointer()); + } + + [TestMethod] + [SuppressMessage("ReSharper", "PossibleNullReferenceException")] + public void TestNewobj() //https://ursoft.asuscomm.com:8080/browse/VMP-134?focusedCommentId=15312&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-15312 + { + InitStrings(); + MsilToVmTestCompiler c = new MsilToVmTestCompilerVmp(); + var mi = typeof (UnitTestCombine).GetMethod("StatNewobj"); + var no = (ClassNewobj)c.Invoke(new object[] {new IntPtr(ClassNewobj.Check)}, + c.CreateVmStream(mi.ReturnType, mi.GetParameters(), + mi.GetMethodBody().LocalVariables.Select(o => o.LocalType).ToArray(), mi.GetMethodBody().GetILAsByteArray())); + Assert.AreEqual(ClassNewobj.Check, no.Ptr); + } + + private static DynamicMethod DynBranch2Op(KeyValuePair<OpCode, CodeTemplate> op, Type[] types) + { + var dyn = new DynamicMethod(op.Key.Name, typeof(bool), types, typeof(void), true); + var gen = dyn.GetILGenerator(); + var retTrue = gen.DefineLabel(); + var endOfMthd = gen.DefineLabel(); + + gen.Emit(OpCodes.Ldarg_1); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(op.Key, retTrue); + + gen.Emit(OpCodes.Ldc_I4_0); + gen.Emit(OpCodes.Br_S, endOfMthd); + + gen.MarkLabel(retTrue); + gen.Emit(OpCodes.Ldc_I4_1); + + gen.MarkLabel(endOfMthd); + gen.Emit(OpCodes.Ret); + return dyn; + } + + private static DynamicMethod Dyn2OpAny(KeyValuePair<OpCode, CodeTemplate> op, Type[] types) + { + Type pushedT; + switch (op.Key.StackBehaviourPush) + { + default: + Assert.Fail("Dyn2OpAny unsupported StackBehaviourPush={0}", op.Key.StackBehaviourPush); + // ReSharper disable once HeuristicUnreachableCode + return null; + case StackBehaviour.Pushi: + pushedT = typeof(Int32); + break; + case StackBehaviour.Pushi8: + pushedT = typeof(Int64); + break; + case StackBehaviour.Pushr4: + pushedT = typeof(float); + break; + case StackBehaviour.Pushr8: + pushedT = typeof(double); + break; + case StackBehaviour.Push1: + pushedT = (op.Key.Value == OpCodes.Shl.Value || op.Key.Value == OpCodes.Shr.Value || op.Key.Value == OpCodes.Shr_Un.Value) ? types[1]: types[0]; + pushedT = CompatibleType(pushedT, types[1], !op.Key.Name.EndsWith("_Un")); + if (pushedT == typeof (object)) pushedT = typeof(IntPtr); + break; + } + return Dyn2Op(op, types, pushedT); + } + + public static Type CompatibleType(Type type0, Type type1, bool signed) + { + if (type0.IsEnum) type0 = type0.GetEnumUnderlyingType(); + if (type1.IsEnum) type1 = type1.GetEnumUnderlyingType(); + if (type0 == typeof (bool) && type1 == typeof (bool)) return typeof (sbyte); // true + true = 2 + if (type0 == typeof (IntPtr)) type0 = IntPtr.Size == 4 ? typeof (Int32) : typeof (Int64); + if (type0 == typeof (UIntPtr)) type0 = IntPtr.Size == 4 ? typeof (UInt32) : typeof (UInt64); + if (type1 == typeof (IntPtr)) type1 = IntPtr.Size == 4 ? typeof (Int32) : typeof (Int64); + if (type1 == typeof (UIntPtr)) type1 = IntPtr.Size == 4 ? typeof (UInt32) : typeof (UInt64); + if (type0 == type1) return type0; + // возвращаем наиболее широкий из типов + return TypeWidth(type0) >= TypeWidth(type1) ? EnsureSign(type0, signed) : EnsureSign(type1, signed); + } + + private static Type EnsureSign(Type t, bool signed) + { + if (t == typeof (Int32)) return signed ? t : typeof (UInt32); + if (t == typeof (UInt32)) return signed ? typeof (Int32) : t; + if (t == typeof (Int64)) return signed ? t : typeof (UInt64); + if (t == typeof (UInt64)) return signed ? typeof (Int64) : t; + return t; + } + + private static int TypeWidth(Type t) + { + if (t.IsEnum) t = t.GetEnumUnderlyingType(); + if (t == typeof (bool)) return 1; + if (t == typeof (byte) || t == typeof (sbyte)) return 2; + if (t == typeof (short) || t == typeof (ushort) || t == typeof(Char)) return 3; + if (t == typeof (int) || t == typeof (uint)) return 4; + if (t == typeof (long) || t == typeof (ulong)) return 5; + if (t == typeof(float)) return 6; + if (t == typeof(double)) return 7; + return 8; // object etc + } + + private static DynamicMethod Dyn2OpBool(KeyValuePair<OpCode, CodeTemplate> op, Type[] types) + { + Type pushedT = typeof(bool); + return Dyn2Op(op, types, pushedT); + } + + private static DynamicMethod Dyn2Op(KeyValuePair<OpCode, CodeTemplate> op, Type[] types, Type ret) + { + var dyn = new DynamicMethod(op.Key.Name, ret, types, typeof(void), true); + var gen = dyn.GetILGenerator(); + + gen.Emit(OpCodes.Ldarg_1); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(op.Key); + + gen.Emit(OpCodes.Ret); + return dyn; + } + } + + internal class MsilToVmTestCompilerVmp : MsilToVmTestCompiler + { + #region opcodes + internal static readonly Dictionary<short, KeyValuePair<OpCode, VMProtect.OpCodes>> IlToVmInstrInfo = new Dictionary<short, KeyValuePair<OpCode, VMProtect.OpCodes>>() + { + { OpCodes.Add.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Add, VMProtect.OpCodes.icAdd) }, + { OpCodes.Add_Ovf.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Add_Ovf, VMProtect.OpCodes.icAdd_ovf) }, + { OpCodes.Add_Ovf_Un.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Add_Ovf_Un, VMProtect.OpCodes.icAdd_ovf_un) }, + { OpCodes.And.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.And, VMProtect.OpCodes.icAnd) }, + //{ OpCodes.Arglist.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Arglist, VMProtect.OpCodes.icArglist) }, + { OpCodes.Beq_S.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Beq_S, VMProtect.OpCodes.icBeq) }, + { OpCodes.Bge_S.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Bge_S, VMProtect.OpCodes.icBge) }, + { OpCodes.Bge_Un_S.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Bge_Un_S, VMProtect.OpCodes.icBge_un) }, + { OpCodes.Bgt_S.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Bgt_S, VMProtect.OpCodes.icBgt) }, + { OpCodes.Bgt_Un_S.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Bgt_Un_S, VMProtect.OpCodes.icBgt_un) }, + { OpCodes.Ble_S.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ble_S, VMProtect.OpCodes.icBle) }, + { OpCodes.Ble_Un_S.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ble_Un_S, VMProtect.OpCodes.icBle_un) }, + { OpCodes.Blt_S.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Blt_S, VMProtect.OpCodes.icBlt) }, + { OpCodes.Blt_Un_S.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Blt_Un_S, VMProtect.OpCodes.icBlt_un) }, + { OpCodes.Bne_Un_S.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Bne_Un_S, VMProtect.OpCodes.icBne_un) }, + //{ OpCodes.Box.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Box, VMProtect.OpCodes.icBox) }, + { OpCodes.Br_S.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Br_S, VMProtect.OpCodes.icBr) }, + //{ OpCodes.Break.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Break, VMProtect.OpCodes.icBreak) }, + //{ OpCodes.Brfalse_S.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Brfalse_S, VMProtect.OpCodes.icBrfalse_S) }, + //{ OpCodes.Brtrue_S.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Brtrue_S, VMProtect.OpCodes.icBrtrue_S) }, + { OpCodes.Call.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Call, VMProtect.OpCodes.icCall) }, + //{ OpCodes.Calli.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Calli, VMProtect.OpCodes.icCalli) }, + //{ OpCodes.Callvirt.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Callvirt, VMProtect.OpCodes.icCallvirt) }, + //{ OpCodes.Castclass.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Castclass, VMProtect.OpCodes.icCastclass) }, + { OpCodes.Ceq.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ceq, VMProtect.OpCodes.icCeq) }, + { OpCodes.Cgt.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Cgt, VMProtect.OpCodes.icCgt) }, + { OpCodes.Cgt_Un.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Cgt_Un, VMProtect.OpCodes.icCgt_un) }, + { OpCodes.Ckfinite.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ckfinite, VMProtect.OpCodes.icCkfinite) }, + { OpCodes.Clt.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Clt, VMProtect.OpCodes.icClt) }, + { OpCodes.Clt_Un.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Clt_Un, VMProtect.OpCodes.icClt_un) }, + //{ OpCodes.Constrained.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Constrained, VMProtect.OpCodes.icConstrained) }, + { OpCodes.Conv_I.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_I, VMProtect.OpCodes.icConv_i) }, + { OpCodes.Conv_I1.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_I1, VMProtect.OpCodes.icConv_i1) }, + { OpCodes.Conv_I2.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_I2, VMProtect.OpCodes.icConv_i2) }, + { OpCodes.Conv_I4.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_I4, VMProtect.OpCodes.icConv_i4) }, + { OpCodes.Conv_I8.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_I8, VMProtect.OpCodes.icConv_i8) }, + { OpCodes.Conv_Ovf_I.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_Ovf_I, VMProtect.OpCodes.icConv_ovf_i) }, + { OpCodes.Conv_Ovf_I_Un.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_Ovf_I_Un, VMProtect.OpCodes.icConv_ovf_i_un) }, + { OpCodes.Conv_Ovf_I1.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_Ovf_I1, VMProtect.OpCodes.icConv_ovf_i1) }, + { OpCodes.Conv_Ovf_I1_Un.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_Ovf_I1_Un, VMProtect.OpCodes.icConv_ovf_i1_un) }, + { OpCodes.Conv_Ovf_I2.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_Ovf_I2, VMProtect.OpCodes.icConv_ovf_i2) }, + { OpCodes.Conv_Ovf_I2_Un.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_Ovf_I2_Un, VMProtect.OpCodes.icConv_ovf_i2_un) }, + { OpCodes.Conv_Ovf_I4.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_Ovf_I4, VMProtect.OpCodes.icConv_ovf_i4) }, + { OpCodes.Conv_Ovf_I4_Un.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_Ovf_I4_Un, VMProtect.OpCodes.icConv_ovf_i4_un) }, + { OpCodes.Conv_Ovf_I8.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_Ovf_I8, VMProtect.OpCodes.icConv_ovf_i8) }, + { OpCodes.Conv_Ovf_I8_Un.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_Ovf_I8_Un, VMProtect.OpCodes.icConv_ovf_i8_un) }, + { OpCodes.Conv_Ovf_U.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_Ovf_U, VMProtect.OpCodes.icConv_ovf_u) }, + { OpCodes.Conv_Ovf_U_Un.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_Ovf_U_Un, VMProtect.OpCodes.icConv_ovf_u_un) }, + { OpCodes.Conv_Ovf_U1.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_Ovf_U1, VMProtect.OpCodes.icConv_ovf_u1) }, + { OpCodes.Conv_Ovf_U1_Un.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_Ovf_U1_Un, VMProtect.OpCodes.icConv_ovf_u1_un) }, + { OpCodes.Conv_Ovf_U2.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_Ovf_U2, VMProtect.OpCodes.icConv_ovf_u2) }, + { OpCodes.Conv_Ovf_U2_Un.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_Ovf_U2_Un, VMProtect.OpCodes.icConv_ovf_u2_un) }, + { OpCodes.Conv_Ovf_U4.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_Ovf_U4, VMProtect.OpCodes.icConv_ovf_u4) }, + { OpCodes.Conv_Ovf_U4_Un.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_Ovf_U4_Un, VMProtect.OpCodes.icConv_ovf_u4_un) }, + { OpCodes.Conv_Ovf_U8.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_Ovf_U8, VMProtect.OpCodes.icConv_ovf_u8) }, + { OpCodes.Conv_Ovf_U8_Un.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_Ovf_U8_Un, VMProtect.OpCodes.icConv_ovf_u8_un) }, + { OpCodes.Conv_R_Un.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_R_Un, VMProtect.OpCodes.icConv_r_un) }, + { OpCodes.Conv_R4.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_R4, VMProtect.OpCodes.icConv_r4) }, + { OpCodes.Conv_R8.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_R8, VMProtect.OpCodes.icConv_r8) }, + { OpCodes.Conv_U.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_U, VMProtect.OpCodes.icConv_u) }, + { OpCodes.Conv_U1.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_U1, VMProtect.OpCodes.icConv_u1) }, + { OpCodes.Conv_U2.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_U2, VMProtect.OpCodes.icConv_u2) }, + { OpCodes.Conv_U4.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_U4, VMProtect.OpCodes.icConv_u4) }, + { OpCodes.Conv_U8.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Conv_U8, VMProtect.OpCodes.icConv_u8) }, + //{ OpCodes.Cpblk.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Cpblk, VMProtect.OpCodes.icCpblk) }, + //{ OpCodes.Cpobj.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Cpobj, VMProtect.OpCodes.icCpobj) }, + { OpCodes.Div.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Div, VMProtect.OpCodes.icDiv) }, + { OpCodes.Div_Un.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Div_Un, VMProtect.OpCodes.icDiv_un) }, + //{ OpCodes.Dup.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Dup, VMProtect.OpCodes.icDup) }, + //{ OpCodes.Endfilter.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Endfilter, VMProtect.OpCodes.icEndfilter) }, + //{ OpCodes.Endfinally.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Endfinally, VMProtect.OpCodes.icEndfinally) }, + //{ OpCodes.Initblk.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Initblk, VMProtect.OpCodes.icInitblk) }, + //{ OpCodes.Initobj.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Initobj, VMProtect.OpCodes.icInitobj) }, + //{ OpCodes.Isinst.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Isinst, VMProtect.OpCodes.icIsinst) }, + //{ OpCodes.Jmp.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Jmp, VMProtect.OpCodes.icJmp) }, + //{ OpCodes.Ldarg.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldarg, VMProtect.OpCodes.icLdarg) }, + { OpCodes.Ldarg_0.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldarg_0, VMProtect.OpCodes.icLdarg_0) }, + { OpCodes.Ldarg_1.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldarg_1, VMProtect.OpCodes.icLdarg_1) }, + //{ OpCodes.Ldarg_2.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldarg_2, VMProtect.OpCodes.icLdarg_2) }, + //{ OpCodes.Ldarg_3.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldarg_3, VMProtect.OpCodes.icLdarg_3) }, + //{ OpCodes.Ldarg_S.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldarg_S, VMProtect.OpCodes.icLdarg_S) }, + //{ OpCodes.Ldarga.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldarga, VMProtect.OpCodes.icLdarga) }, + { OpCodes.Ldarga_S.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldarga_S, VMProtect.OpCodes.icLdarga_s) }, + { OpCodes.Ldc_I4.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldc_I4, VMProtect.OpCodes.icLdc_i4) }, + { OpCodes.Ldc_I4_0.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldc_I4_0, VMProtect.OpCodes.icLdc_i4_0) }, + { OpCodes.Ldc_I4_1.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldc_I4_1, VMProtect.OpCodes.icLdc_i4_1) }, + { OpCodes.Ldc_I4_2.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldc_I4_2, VMProtect.OpCodes.icLdc_i4_2) }, + //{ OpCodes.Ldc_I4_3.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldc_I4_3, VMProtect.OpCodes.icLdc_I4_3) }, + //{ OpCodes.Ldc_I4_4.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldc_I4_4, VMProtect.OpCodes.icLdc_I4_4) }, + //{ OpCodes.Ldc_I4_5.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldc_I4_5, VMProtect.OpCodes.icLdc_I4_5) }, + //{ OpCodes.Ldc_I4_6.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldc_I4_6, VMProtect.OpCodes.icLdc_I4_6) }, + //{ OpCodes.Ldc_I4_7.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldc_I4_7, VMProtect.OpCodes.icLdc_I4_7) }, + //{ OpCodes.Ldc_I4_8.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldc_I4_8, VMProtect.OpCodes.icLdc_I4_8) }, + //{ OpCodes.Ldc_I4_M1.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldc_I4_M1, VMProtect.OpCodes.icLdc_I4_M1) }, + //{ OpCodes.Ldc_I4_S.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldc_I4_S, VMProtect.OpCodes.icLdc_I4_S) }, + //{ OpCodes.Ldc_I8.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldc_I8, VMProtect.OpCodes.icLdc_I8) }, + //{ OpCodes.Ldc_R4.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldc_R4, VMProtect.OpCodes.icLdc_R4) }, + //{ OpCodes.Ldc_R8.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldc_R8, VMProtect.OpCodes.icLdc_R8) }, + //{ OpCodes.Ldelem.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldelem, VMProtect.OpCodes.icLdelem) }, + //{ OpCodes.Ldelem_I.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldelem_I, VMProtect.OpCodes.icLdelem_I) }, + //{ OpCodes.Ldelem_I1.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldelem_I1, VMProtect.OpCodes.icLdelem_I1) }, + //{ OpCodes.Ldelem_I2.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldelem_I2, VMProtect.OpCodes.icLdelem_I2) }, + //{ OpCodes.Ldelem_I4.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldelem_I4, VMProtect.OpCodes.icLdelem_I4) }, + //{ OpCodes.Ldelem_I8.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldelem_I8, VMProtect.OpCodes.icLdelem_I8) }, + //{ OpCodes.Ldelem_R4.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldelem_R4, VMProtect.OpCodes.icLdelem_R4) }, + //{ OpCodes.Ldelem_R8.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldelem_R8, VMProtect.OpCodes.icLdelem_R8) }, + //{ OpCodes.Ldelem_Ref.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldelem_Ref, VMProtect.OpCodes.icLdelem_Ref) }, + //{ OpCodes.Ldelem_U1.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldelem_U1, VMProtect.OpCodes.icLdelem_U1) }, + //{ OpCodes.Ldelem_U2.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldelem_U2, VMProtect.OpCodes.icLdelem_U2) }, + //{ OpCodes.Ldelem_U4.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldelem_U4, VMProtect.OpCodes.icLdelem_U4) }, + //{ OpCodes.Ldelema.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldelema, VMProtect.OpCodes.icLdelema) }, + //{ OpCodes.Ldfld.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldfld, VMProtect.OpCodes.icLdfld) }, + //{ OpCodes.Ldflda.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldflda, VMProtect.OpCodes.icLdflda) }, + //{ OpCodes.Ldftn.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldftn, VMProtect.OpCodes.icLdftn) }, + //{ OpCodes.Ldind_I.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldind_I, VMProtect.OpCodes.icLdind_I) }, + //{ OpCodes.Ldind_I1.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldind_I1, VMProtect.OpCodes.icLdind_I1) }, + //{ OpCodes.Ldind_I2.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldind_I2, VMProtect.OpCodes.icLdind_I2) }, + //{ OpCodes.Ldind_I4.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldind_I4, VMProtect.OpCodes.icLdind_I4) }, + //{ OpCodes.Ldind_I8.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldind_I8, VMProtect.OpCodes.icLdind_I8) }, + //{ OpCodes.Ldind_R4.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldind_R4, VMProtect.OpCodes.icLdind_R4) }, + //{ OpCodes.Ldind_R8.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldind_R8, VMProtect.OpCodes.icLdind_R8) }, + //{ OpCodes.Ldind_Ref.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldind_Ref, VMProtect.OpCodes.icLdind_Ref) }, + //{ OpCodes.Ldind_U1.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldind_U1, VMProtect.OpCodes.icLdind_U1) }, + //{ OpCodes.Ldind_U2.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldind_U2, VMProtect.OpCodes.icLdind_U2) }, + //{ OpCodes.Ldind_U4.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldind_U4, VMProtect.OpCodes.icLdind_U4) }, + //{ OpCodes.Ldlen.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldlen, VMProtect.OpCodes.icLdlen) }, + //{ OpCodes.Ldloc.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldloc, VMProtect.OpCodes.icLdloc) }, + { OpCodes.Ldloc_0.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldloc_0, VMProtect.OpCodes.icLdloc_0) }, + //{ OpCodes.Ldloc_1.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldloc_1, VMProtect.OpCodes.icLdloc_1) }, + //{ OpCodes.Ldloc_2.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldloc_2, VMProtect.OpCodes.icLdloc_2) }, + //{ OpCodes.Ldloc_3.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldloc_3, VMProtect.OpCodes.icLdloc_3) }, + //{ OpCodes.Ldloc_S.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldloc_S, VMProtect.OpCodes.icLdloc_S) }, + //{ OpCodes.Ldloca.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldloca, VMProtect.OpCodes.icLdloca) }, + //{ OpCodes.Ldloca_S.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldloca_S, VMProtect.OpCodes.icLdloca_S) }, + { OpCodes.Ldnull.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldnull, VMProtect.OpCodes.icLdnull) }, + //{ OpCodes.Ldobj.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldobj, VMProtect.OpCodes.icLdobj) }, + //{ OpCodes.Ldsfld.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldsfld, VMProtect.OpCodes.icLdsfld) }, + //{ OpCodes.Ldsflda.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldsflda, VMProtect.OpCodes.icLdsflda) }, + //{ OpCodes.Ldstr.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldstr, VMProtect.OpCodes.icLdstr) }, + //{ OpCodes.Ldtoken.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldtoken, VMProtect.OpCodes.icLdtoken) }, + //{ OpCodes.Ldvirtftn.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ldvirtftn, VMProtect.OpCodes.icLdvirtftn) }, + //{ OpCodes.Leave.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Leave, VMProtect.OpCodes.icLeave) }, + //{ OpCodes.Leave_S.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Leave_S, VMProtect.OpCodes.icLeave_S) }, + //{ OpCodes.Localloc.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Localloc, VMProtect.OpCodes.icLocalloc) }, + //{ OpCodes.Mkrefany.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Mkrefany, VMProtect.OpCodes.icMkrefany) }, + { OpCodes.Mul.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Mul, VMProtect.OpCodes.icMul) }, + { OpCodes.Mul_Ovf.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Mul_Ovf, VMProtect.OpCodes.icMul_ovf) }, + { OpCodes.Mul_Ovf_Un.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Mul_Ovf_Un, VMProtect.OpCodes.icMul_ovf_un) }, + //{ OpCodes.Neg.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Neg, VMProtect.OpCodes.icNeg) }, + //{ OpCodes.Newarr.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Newarr, VMProtect.OpCodes.icNewarr) }, + { OpCodes.Newobj.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Newobj, VMProtect.OpCodes.icNewobj) }, + { OpCodes.Nop.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Nop, VMProtect.OpCodes.icNop) }, + { OpCodes.Not.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Not, VMProtect.OpCodes.icNot) }, + { OpCodes.Or.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Or, VMProtect.OpCodes.icOr) }, + //{ OpCodes.Pop.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Pop, VMProtect.OpCodes.icPop) }, + //{ OpCodes.Prefix1.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Prefix1, VMProtect.OpCodes.icPrefix1) }, + //{ OpCodes.Prefix2.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Prefix2, VMProtect.OpCodes.icPrefix2) }, + //{ OpCodes.Prefix3.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Prefix3, VMProtect.OpCodes.icPrefix3) }, + //{ OpCodes.Prefix4.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Prefix4, VMProtect.OpCodes.icPrefix4) }, + //{ OpCodes.Prefix5.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Prefix5, VMProtect.OpCodes.icPrefix5) }, + //{ OpCodes.Prefix6.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Prefix6, VMProtect.OpCodes.icPrefix6) }, + //{ OpCodes.Prefix7.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Prefix7, VMProtect.OpCodes.icPrefix7) }, + //{ OpCodes.Prefixref.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Prefixref, VMProtect.OpCodes.icPrefixref) }, + //{ OpCodes.Readonly.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Readonly, VMProtect.OpCodes.icReadonly) }, + //{ OpCodes.Refanytype.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Refanytype, VMProtect.OpCodes.icRefanytype) }, + //{ OpCodes.Refanyval.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Refanyval, VMProtect.OpCodes.icRefanyval) }, + { OpCodes.Rem.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Rem, VMProtect.OpCodes.icRem) }, + { OpCodes.Rem_Un.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Rem_Un, VMProtect.OpCodes.icRem_un) }, + { OpCodes.Ret.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Ret, VMProtect.OpCodes.icRet) }, + //{ OpCodes.Rethrow.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Rethrow, VMProtect.OpCodes.icRethrow) }, + { OpCodes.Shl.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Shl, VMProtect.OpCodes.icShl) }, + { OpCodes.Shr.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Shr, VMProtect.OpCodes.icShr) }, + { OpCodes.Shr_Un.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Shr_Un, VMProtect.OpCodes.icShr_un) }, + //{ OpCodes.Sizeof.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Sizeof, VMProtect.OpCodes.icSizeof) }, + //{ OpCodes.Starg.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Starg, VMProtect.OpCodes.icStarg) }, + //{ OpCodes.Starg_S.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Starg_S, VMProtect.OpCodes.icStarg_S) }, + //{ OpCodes.Stelem.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stelem, VMProtect.OpCodes.icStelem) }, + //{ OpCodes.Stelem_I.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stelem_I, VMProtect.OpCodes.icStelem_I) }, + //{ OpCodes.Stelem_I1.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stelem_I1, VMProtect.OpCodes.icStelem_I1) }, + { OpCodes.Stelem_I2.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stelem_I2, VMProtect.OpCodes.icStelem_i2) }, + //{ OpCodes.Stelem_I4.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stelem_I4, VMProtect.OpCodes.icStelem_I4) }, + //{ OpCodes.Stelem_I8.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stelem_I8, VMProtect.OpCodes.icStelem_I8) }, + //{ OpCodes.Stelem_R4.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stelem_R4, VMProtect.OpCodes.icStelem_R4) }, + //{ OpCodes.Stelem_R8.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stelem_R8, VMProtect.OpCodes.icStelem_R8) }, + //{ OpCodes.Stelem_Ref.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stelem_Ref, VMProtect.OpCodes.icStelem_Ref) }, + //{ OpCodes.Stfld.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stfld, VMProtect.OpCodes.icStfld) }, + //{ OpCodes.Stind_I.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stind_I, VMProtect.OpCodes.icStind_I) }, + //{ OpCodes.Stind_I1.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stind_I1, VMProtect.OpCodes.icStind_I1) }, + //{ OpCodes.Stind_I2.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stind_I2, VMProtect.OpCodes.icStind_I2) }, + //{ OpCodes.Stind_I4.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stind_I4, VMProtect.OpCodes.icStind_I4) }, + //{ OpCodes.Stind_I8.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stind_I8, VMProtect.OpCodes.icStind_I8) }, + //{ OpCodes.Stind_R4.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stind_R4, VMProtect.OpCodes.icStind_R4) }, + //{ OpCodes.Stind_R8.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stind_R8, VMProtect.OpCodes.icStind_R8) }, + //{ OpCodes.Stind_Ref.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stind_Ref, VMProtect.OpCodes.icStind_Ref) }, + //{ OpCodes.Stloc.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stloc, VMProtect.OpCodes.icStloc) }, + { OpCodes.Stloc_0.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stloc_0, VMProtect.OpCodes.icStloc_0) }, + //{ OpCodes.Stloc_1.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stloc_1, VMProtect.OpCodes.icStloc_1) }, + //{ OpCodes.Stloc_2.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stloc_2, VMProtect.OpCodes.icStloc_2) }, + //{ OpCodes.Stloc_3.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stloc_3, VMProtect.OpCodes.icStloc_3) }, + //{ OpCodes.Stloc_S.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stloc_S, VMProtect.OpCodes.icStloc_S) }, + //{ OpCodes.Stobj.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stobj, VMProtect.OpCodes.icStobj) }, + //{ OpCodes.Stsfld.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Stsfld, VMProtect.OpCodes.icStsfld) }, + { OpCodes.Sub.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Sub, VMProtect.OpCodes.icSub) }, + { OpCodes.Sub_Ovf.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Sub_Ovf, VMProtect.OpCodes.icSub_ovf) }, + { OpCodes.Sub_Ovf_Un.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Sub_Ovf_Un, VMProtect.OpCodes.icSub_ovf_un) }, + //{ OpCodes.Switch.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Switch, VMProtect.OpCodes.icSwitch) }, + //{ OpCodes.Tailcall.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Tailcall, VMProtect.OpCodes.icTailcall) }, + //{ OpCodes.Throw.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Throw, VMProtect.OpCodes.icThrow) }, + //{ OpCodes.Unaligned.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Unaligned, VMProtect.OpCodes.icUnaligned) }, + //{ OpCodes.Unbox.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Unbox, VMProtect.OpCodes.icUnbox) }, + //{ OpCodes.Unbox_Any.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Unbox_Any, VMProtect.OpCodes.icUnbox_Any) }, + //{ OpCodes.Volatile.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Volatile, VMProtect.OpCodes.icVolatile) }, + { OpCodes.Xor.Value, new KeyValuePair<OpCode, VMProtect.OpCodes>(OpCodes.Xor, VMProtect.OpCodes.icXor) }, + }; + #endregion + private static readonly Dictionary<Type, int> TypeTokenInModule = new Dictionary<Type, int>(); //TypeDefs and TypeRefs + private static int GetTypeTokenInModule(Type t) + { + var tryToken = 0x01000001; //first TypeRef + var m = typeof (MsilToVmTestCompilerVmp).Module; + while (true) + { + try + { + Type t1 = m.ResolveType(tryToken); + TypeTokenInModule.Add(t1, tryToken++); + } + catch (Exception) + { + break; //until last TypeRef + } + + } + if (TypeTokenInModule.ContainsKey(t)) + return TypeTokenInModule[t]; + if (t.Module == m) + { + TypeTokenInModule.Add(t, t.MetadataToken); + return t.MetadataToken; + } + Assert.Fail("Bad type {0}: not accessible from this module", t); + return 0; + } + public override Stream CreateVmStream(Type rt, ParameterInfo[] pi, Type[] locals, byte[] ilBytes) + { + var ret = new MemoryStream(); + var wr = new BinaryWriter(ret); + var fwdTypeDefs = new Dictionary<Type, int>(); + var fwdTypeRefs = new Dictionary<int, Type>(); + var deferredBrTargets = new Dictionary<long, UInt32>(); + var srcToDstInstrPositions = new Dictionary<long, UInt32>(); + const int dummy = 0x55555555; + fwdTypeDefs.Add(rt, dummy); + var pars = pi; + foreach (var parameterInfo in pars) + { + if (!fwdTypeDefs.ContainsKey(parameterInfo.ParameterType)) + fwdTypeDefs.Add(parameterInfo.ParameterType, dummy); + wr.Write((byte)VMProtect.OpCodes.icInitarg); + fwdTypeRefs.Add((int)ret.Position, parameterInfo.ParameterType); + wr.Write(dummy); // parTypeId fwd ref + } + foreach (var lt in locals) + { + if (!fwdTypeDefs.ContainsKey(lt)) + fwdTypeDefs.Add(lt, dummy); + // FIXME + //wr.Write((byte)VMProtect.OpCodes.icInitloc); + fwdTypeRefs.Add((int)ret.Position, lt); + wr.Write(dummy); // parTypeId fwd ref + } + + using (var sr = new BinaryReader(new MemoryStream(ilBytes))) + { + while (sr.BaseStream.Position < sr.BaseStream.Length) + { + srcToDstInstrPositions[sr.BaseStream.Position] = (uint)ret.Position; + short ilByte = sr.ReadByte(); + if (ilByte == 0xFE) + ilByte = (short)((ilByte << 8) | sr.ReadByte()); + Assert.IsTrue(IlToVmInstrInfo.ContainsKey(ilByte), "Extend IlToVmInstrInfo with {0:X} or use short jump", ilByte); + var vmInstrInfo = IlToVmInstrInfo[ilByte]; + ulong operand = 0; + switch (vmInstrInfo.Key.OperandType) + { + case OperandType.InlineNone: + break; + case OperandType.InlineI8: + case OperandType.InlineR: + operand = sr.ReadUInt64(); + break; + case OperandType.InlineVar: + operand = sr.ReadUInt16(); + break; + case OperandType.ShortInlineBrTarget: + case OperandType.ShortInlineI: + case OperandType.ShortInlineVar: + operand = sr.ReadByte(); + break; + default: + operand = sr.ReadUInt32(); + break; + } + switch ((short)vmInstrInfo.Value) + { + case (short)VMProtect.OpCodes.icNop: + continue; + case (short)VMProtect.OpCodes.icStloc_0: + wr.Write((byte)VMProtect.OpCodes.icStloc); + wr.Write((ushort)0); + break; + case (short)VMProtect.OpCodes.icStloc_1: + wr.Write((byte)VMProtect.OpCodes.icStloc); + wr.Write((ushort)1); + break; + case (short)VMProtect.OpCodes.icStloc_2: + wr.Write((byte)VMProtect.OpCodes.icStloc); + wr.Write((ushort)2); + break; + case (short)VMProtect.OpCodes.icStloc_3: + wr.Write((byte)VMProtect.OpCodes.icStloc); + wr.Write((ushort)3); + break; + case (short)VMProtect.OpCodes.icLdloc_0: + wr.Write((byte)VMProtect.OpCodes.icLdloc); + wr.Write((ushort)0); + break; + case (short)VMProtect.OpCodes.icLdloc_1: + wr.Write((byte)VMProtect.OpCodes.icLdloc); + wr.Write((ushort)1); + break; + case (short)VMProtect.OpCodes.icLdloc_2: + wr.Write((byte)VMProtect.OpCodes.icLdloc); + wr.Write((ushort)2); + break; + case (short)VMProtect.OpCodes.icLdloc_3: + wr.Write((byte)VMProtect.OpCodes.icLdloc); + wr.Write((ushort)3); + break; + case (short)VMProtect.OpCodes.icLdarg_0: + wr.Write((byte)VMProtect.OpCodes.icLdarg); + wr.Write((ushort)0); + break; + case (short)VMProtect.OpCodes.icLdarg_1: + wr.Write((byte)VMProtect.OpCodes.icLdarg); + wr.Write((ushort)1); + break; + case (short)VMProtect.OpCodes.icLdarg_2: + wr.Write((byte)VMProtect.OpCodes.icLdarg); + wr.Write((ushort)2); + break; + case (short)VMProtect.OpCodes.icLdarg_3: + wr.Write((byte)VMProtect.OpCodes.icLdarg); + wr.Write((ushort)3); + break; + case (short)VMProtect.OpCodes.icLdarga_s: + wr.Write((byte)VMProtect.OpCodes.icLdarga); + wr.Write((ushort)operand); + break; + case (short)VMProtect.OpCodes.icRet: + wr.Write((byte)VMProtect.OpCodes.icRet); + fwdTypeRefs.Add((int)ret.Position, rt); + wr.Write(dummy); // ReturnTypeId fwd ref + break; + case (short)VMProtect.OpCodes.icLdc_i4_0: + wr.Write((byte)VMProtect.OpCodes.icLdc_i4); + wr.Write((uint)0); + break; + case (short)VMProtect.OpCodes.icLdc_i4_1: + wr.Write((byte)VMProtect.OpCodes.icLdc_i4); + wr.Write((uint)1); + break; + case (short)VMProtect.OpCodes.icLdc_i4_2: + wr.Write((byte)VMProtect.OpCodes.icLdc_i4); + wr.Write((uint)2); + break; + case (short)VMProtect.OpCodes.icLdc_i4_3: + wr.Write((byte)VMProtect.OpCodes.icLdc_i4); + wr.Write((uint)3); + break; + case (short)VMProtect.OpCodes.icBr: + wr.Write((byte)VMProtect.OpCodes.icLdc_i4); + deferredBrTargets[ret.Position] = (uint)sr.BaseStream.Position + (uint)operand; + wr.Write(dummy); + wr.Write((byte)VMProtect.OpCodes.icBr); + break; + case (short)VMProtect.OpCodes.icBeq: + case (short)VMProtect.OpCodes.icBne_un: + case (short)VMProtect.OpCodes.icBlt: + case (short)VMProtect.OpCodes.icBlt_un: + case (short)VMProtect.OpCodes.icBle: + case (short)VMProtect.OpCodes.icBle_un: + case (short)VMProtect.OpCodes.icBgt: + case (short)VMProtect.OpCodes.icBgt_un: + case (short)VMProtect.OpCodes.icBge: + case (short)VMProtect.OpCodes.icBge_un: + case (short)VMProtect.OpCodes.icBrtrue: + case (short)VMProtect.OpCodes.icBrfalse: + switch ((short)vmInstrInfo.Value) + { + // FIXME + /* + case (short)VMProtect.OpCodes.icBeq: + case (short)VMProtect.OpCodes.icBne_un: + wr.Write((byte)VMProtect.OpCodes.icCeq); + break; + case (short)VMProtect.OpCodes.icBge: + wr.Write((byte)VMProtect.OpCodes.icCge); + break; + case (short)VMProtect.OpCodes.icBge_un: + wr.Write((byte)VMProtect.OpCodes.icCge_un); + break; + case (short)VMProtect.OpCodes.icBlt: + wr.Write((byte)VMProtect.OpCodes.icClt); + break; + case (short)VMProtect.OpCodes.icBlt_un: + wr.Write((byte)VMProtect.OpCodes.icClt_un); + break; + case (short)VMProtect.OpCodes.icBle: + wr.Write((byte)VMProtect.OpCodes.icCle); + break; + case (short)VMProtect.OpCodes.icBle_un: + wr.Write((byte)VMProtect.OpCodes.icCle_un); + break; + case (short)VMProtect.OpCodes.icBgt: + wr.Write((byte)VMProtect.OpCodes.icCgt); + break; + case (short)VMProtect.OpCodes.icBgt_un: + wr.Write((byte)VMProtect.OpCodes.icCgt_un); + break; + */ + } + // FIXME + //wr.Write((byte)VMProtect.OpCodes.icConv_b); + wr.Write((byte)VMProtect.OpCodes.icNeg); + switch ((short)vmInstrInfo.Value) + { + case (short)VMProtect.OpCodes.icBne_un: + //case (short)VMProtect.OpCodes.icBle: + //case (short)VMProtect.OpCodes.icBle_un: + //case (short)VMProtect.OpCodes.icBge: + //case (short)VMProtect.OpCodes.icBge_un: + case (short)VMProtect.OpCodes.icBrfalse: + wr.Write((byte)VMProtect.OpCodes.icNot); + break; + } + wr.Write((byte)VMProtect.OpCodes.icLdc_i4); + deferredBrTargets[ret.Position] = (uint)sr.BaseStream.Position + (uint)operand; + wr.Write(dummy); + wr.Write((byte)VMProtect.OpCodes.icAnd); + wr.Write((byte)VMProtect.OpCodes.icDup); + // FIXME + //wr.Write((byte)VMProtect.OpCodes.icConv_b); + wr.Write((byte)VMProtect.OpCodes.icNeg); + wr.Write((byte)VMProtect.OpCodes.icNot); + wr.Write((byte)VMProtect.OpCodes.icLdc_i4); + deferredBrTargets[ret.Position] = (uint)sr.BaseStream.Position; + wr.Write(dummy); + wr.Write((byte)VMProtect.OpCodes.icAnd); + wr.Write((byte)VMProtect.OpCodes.icAdd); + wr.Write((byte)VMProtect.OpCodes.icBr); + break; + default: + wr.Write((byte)vmInstrInfo.Value); + break; + } + wr.Flush(); + } + foreach (var t in fwdTypeDefs.Keys.ToArray()) + { + fwdTypeDefs[t] = GetTypeTokenInModule(t); + } + foreach (var r in fwdTypeRefs) + { + ret.Position = r.Key; + wr.Write(fwdTypeDefs[r.Value]); + wr.Flush(); + } + foreach (var r in deferredBrTargets) + { + ret.Position = r.Key; + var srcPos = r.Value; + wr.Write(srcToDstInstrPositions[srcPos]); + wr.Flush(); + } + ret.Position = 0; + return ret; + } + } + + public override object Invoke(object[] parameters, Stream vmStream) + { + var contents = new BinaryReader(vmStream).ReadBytes((int) vmStream.Length); + var unmanagedPointer = Marshal.AllocHGlobal(contents.Length); + Marshal.Copy(contents, 0, unmanagedPointer, contents.Length); + var vm = new VirtualMachine(); + // ReSharper disable once PossibleNullReferenceException + typeof(VirtualMachine).GetField("_instance", BindingFlags.Instance | BindingFlags.NonPublic) + .SetValue(vm, unmanagedPointer.ToInt64()); + var vmRet = vm.Invoke(parameters, 0); + Marshal.FreeHGlobal(unmanagedPointer); + return vmRet; + } + } + + public class MsilToVmTestCompilerRefVm : MsilToVmTestCompiler + { + public static readonly VmInstrCodesDb InstrCodesDb = new VmInstrCodesDb(); + #region opcodes + public static readonly Dictionary<short, KeyValuePair<OpCode, VmInstrInfo>> IlToVmInstrInfo = new Dictionary<short, KeyValuePair<OpCode, VmInstrInfo>>() + { + { OpCodes.Add.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Add, InstrCodesDb.Add_) }, + { OpCodes.Add_Ovf.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Add_Ovf, InstrCodesDb.Add_ovf_) }, + { OpCodes.Add_Ovf_Un.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Add_Ovf_Un, InstrCodesDb.Add_ovf_un_) }, + { OpCodes.And.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.And, InstrCodesDb.And_) }, + //{ OpCodes.Arglist.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Arglist, InstrCodesDb.Arglist_) }, + { OpCodes.Beq_S.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Beq_S, InstrCodesDb.Beq_) }, + { OpCodes.Bge_S.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Bge_S, InstrCodesDb.Bge_) }, + { OpCodes.Bge_Un_S.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Bge_Un_S, InstrCodesDb.Bge_un_) }, + { OpCodes.Bgt_S.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Bgt_S, InstrCodesDb.Bgt_) }, + { OpCodes.Bgt_Un_S.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Bgt_Un_S, InstrCodesDb.Bgt_un_) }, + { OpCodes.Ble_S.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ble_S, InstrCodesDb.Ble_) }, + { OpCodes.Ble_Un_S.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ble_Un_S, InstrCodesDb.Ble_un_) }, + { OpCodes.Blt_S.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Blt_S, InstrCodesDb.Blt_) }, + { OpCodes.Blt_Un_S.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Blt_Un_S, InstrCodesDb.Blt_un_) }, + { OpCodes.Bne_Un_S.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Bne_Un_S, InstrCodesDb.Bne_un_) }, + //{ OpCodes.Box.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Box, InstrCodesDb.Box_) }, + { OpCodes.Br_S.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Br_S, InstrCodesDb.Br_) }, + //{ OpCodes.Break.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Break, InstrCodesDb.Break_) }, + //{ OpCodes.Brfalse_S.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Brfalse_S, InstrCodesDb.Brfalse_S_) }, + //{ OpCodes.Brtrue_S.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Brtrue_S, InstrCodesDb.Brtrue_S_) }, + { OpCodes.Call.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Call, InstrCodesDb.Call_) }, + //{ OpCodes.Calli.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Calli, InstrCodesDb.Calli_) }, + //{ OpCodes.Callvirt.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Callvirt, InstrCodesDb.Callvirt_) }, + //{ OpCodes.Castclass.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Castclass, InstrCodesDb.Castclass_) }, + { OpCodes.Ceq.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ceq, InstrCodesDb.Ceq_) }, + { OpCodes.Cgt.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Cgt, InstrCodesDb.Cgt_) }, + { OpCodes.Cgt_Un.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Cgt_Un, InstrCodesDb.Cgt_un_) }, + { OpCodes.Ckfinite.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ckfinite, InstrCodesDb.Ckfinite_) }, + { OpCodes.Clt.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Clt, InstrCodesDb.Clt_) }, + { OpCodes.Clt_Un.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Clt_Un, InstrCodesDb.Clt_un_) }, + //{ OpCodes.Constrained.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Constrained, InstrCodesDb.Constrained_) }, + { OpCodes.Conv_I.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_I, InstrCodesDb.Conv_i_) }, + { OpCodes.Conv_I1.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_I1, InstrCodesDb.Conv_i1_) }, + { OpCodes.Conv_I2.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_I2, InstrCodesDb.Conv_i2_) }, + { OpCodes.Conv_I4.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_I4, InstrCodesDb.Conv_i4_) }, + { OpCodes.Conv_I8.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_I8, InstrCodesDb.Conv_i8_) }, + { OpCodes.Conv_Ovf_I.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_Ovf_I, InstrCodesDb.Conv_ovf_i_) }, + { OpCodes.Conv_Ovf_I_Un.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_Ovf_I_Un, InstrCodesDb.Conv_ovf_i_un_) }, + { OpCodes.Conv_Ovf_I1.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_Ovf_I1, InstrCodesDb.Conv_ovf_i1_) }, + { OpCodes.Conv_Ovf_I1_Un.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_Ovf_I1_Un, InstrCodesDb.Conv_ovf_i1_un_) }, + { OpCodes.Conv_Ovf_I2.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_Ovf_I2, InstrCodesDb.Conv_ovf_i2_) }, + { OpCodes.Conv_Ovf_I2_Un.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_Ovf_I2_Un, InstrCodesDb.Conv_ovf_i2_un_) }, + { OpCodes.Conv_Ovf_I4.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_Ovf_I4, InstrCodesDb.Conv_ovf_i4_) }, + { OpCodes.Conv_Ovf_I4_Un.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_Ovf_I4_Un, InstrCodesDb.Conv_ovf_i4_un_) }, + { OpCodes.Conv_Ovf_I8.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_Ovf_I8, InstrCodesDb.Conv_ovf_i8_) }, + { OpCodes.Conv_Ovf_I8_Un.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_Ovf_I8_Un, InstrCodesDb.Conv_ovf_i8_un_) }, + { OpCodes.Conv_Ovf_U.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_Ovf_U, InstrCodesDb.Conv_ovf_u_) }, + { OpCodes.Conv_Ovf_U_Un.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_Ovf_U_Un, InstrCodesDb.Conv_ovf_u_un_) }, + { OpCodes.Conv_Ovf_U1.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_Ovf_U1, InstrCodesDb.Conv_ovf_u1_) }, + { OpCodes.Conv_Ovf_U1_Un.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_Ovf_U1_Un, InstrCodesDb.Conv_ovf_u1_un_) }, + { OpCodes.Conv_Ovf_U2.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_Ovf_U2, InstrCodesDb.Conv_ovf_u2_) }, + { OpCodes.Conv_Ovf_U2_Un.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_Ovf_U2_Un, InstrCodesDb.Conv_ovf_u2_un_) }, + { OpCodes.Conv_Ovf_U4.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_Ovf_U4, InstrCodesDb.Conv_ovf_u4_) }, + { OpCodes.Conv_Ovf_U4_Un.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_Ovf_U4_Un, InstrCodesDb.Conv_ovf_u4_un_) }, + { OpCodes.Conv_Ovf_U8.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_Ovf_U8, InstrCodesDb.Conv_ovf_u8_) }, + { OpCodes.Conv_Ovf_U8_Un.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_Ovf_U8_Un, InstrCodesDb.Conv_ovf_u8_un_) }, + { OpCodes.Conv_R_Un.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_R_Un, InstrCodesDb.Conv_r_un_) }, + { OpCodes.Conv_R4.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_R4, InstrCodesDb.Conv_r4_) }, + { OpCodes.Conv_R8.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_R8, InstrCodesDb.Conv_r8_) }, + { OpCodes.Conv_U.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_U, InstrCodesDb.Conv_u_) }, + { OpCodes.Conv_U1.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_U1, InstrCodesDb.Conv_u1_) }, + { OpCodes.Conv_U2.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_U2, InstrCodesDb.Conv_u2_) }, + { OpCodes.Conv_U4.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_U4, InstrCodesDb.Conv_u4_) }, + { OpCodes.Conv_U8.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Conv_U8, InstrCodesDb.Conv_u8_) }, + //{ OpCodes.Cpblk.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Cpblk, InstrCodesDb.Cpblk_) }, + //{ OpCodes.Cpobj.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Cpobj, InstrCodesDb.Cpobj_) }, + { OpCodes.Div.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Div, InstrCodesDb.Div_) }, + { OpCodes.Div_Un.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Div_Un, InstrCodesDb.Div_un_) }, + //{ OpCodes.Dup.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Dup, InstrCodesDb.Dup_) }, + //{ OpCodes.Endfilter.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Endfilter, InstrCodesDb.Endfilter_) }, + //{ OpCodes.Endfinally.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Endfinally, InstrCodesDb.Endfinally_) }, + //{ OpCodes.Initblk.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Initblk, InstrCodesDb.Initblk_) }, + //{ OpCodes.Initobj.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Initobj, InstrCodesDb.Initobj_) }, + //{ OpCodes.Isinst.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Isinst, InstrCodesDb.Isinst_) }, + //{ OpCodes.Jmp.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Jmp, InstrCodesDb.Jmp_) }, + //{ OpCodes.Ldarg.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldarg, InstrCodesDb.Ldarg_) }, + { OpCodes.Ldarg_0.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldarg_0, InstrCodesDb.Ldarg_0_) }, + { OpCodes.Ldarg_1.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldarg_1, InstrCodesDb.Ldarg_1_) }, + //{ OpCodes.Ldarg_2.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldarg_2, InstrCodesDb.Ldarg_2_) }, + //{ OpCodes.Ldarg_3.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldarg_3, InstrCodesDb.Ldarg_3_) }, + //{ OpCodes.Ldarg_S.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldarg_S, InstrCodesDb.Ldarg_S_) }, + //{ OpCodes.Ldarga.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldarga, InstrCodesDb.Ldarga_) }, + { OpCodes.Ldarga_S.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldarga_S, InstrCodesDb.Ldarga_s_) }, + //{ OpCodes.Ldc_I4.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldc_I4, InstrCodesDb.Ldc_i4_) }, + { OpCodes.Ldc_I4_0.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldc_I4_0, InstrCodesDb.Ldc_i4_0_) }, + { OpCodes.Ldc_I4_1.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldc_I4_1, InstrCodesDb.Ldc_i4_1_) }, + //{ OpCodes.Ldc_I4_2.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldc_I4_2, InstrCodesDb.Ldc_i4_2_) }, + //{ OpCodes.Ldc_I4_3.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldc_I4_3, InstrCodesDb.Ldc_I4_3_) }, + //{ OpCodes.Ldc_I4_4.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldc_I4_4, InstrCodesDb.Ldc_I4_4_) }, + //{ OpCodes.Ldc_I4_5.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldc_I4_5, InstrCodesDb.Ldc_I4_5_) }, + //{ OpCodes.Ldc_I4_6.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldc_I4_6, InstrCodesDb.Ldc_I4_6_) }, + //{ OpCodes.Ldc_I4_7.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldc_I4_7, InstrCodesDb.Ldc_I4_7_) }, + //{ OpCodes.Ldc_I4_8.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldc_I4_8, InstrCodesDb.Ldc_I4_8_) }, + //{ OpCodes.Ldc_I4_M1.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldc_I4_M1, InstrCodesDb.Ldc_I4_M1_) }, + //{ OpCodes.Ldc_I4_S.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldc_I4_S, InstrCodesDb.Ldc_I4_S_) }, + //{ OpCodes.Ldc_I8.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldc_I8, InstrCodesDb.Ldc_I8_) }, + //{ OpCodes.Ldc_R4.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldc_R4, InstrCodesDb.Ldc_R4_) }, + //{ OpCodes.Ldc_R8.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldc_R8, InstrCodesDb.Ldc_R8_) }, + //{ OpCodes.Ldelem.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldelem, InstrCodesDb.Ldelem_) }, + //{ OpCodes.Ldelem_I.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldelem_I, InstrCodesDb.Ldelem_I_) }, + //{ OpCodes.Ldelem_I1.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldelem_I1, InstrCodesDb.Ldelem_I1_) }, + //{ OpCodes.Ldelem_I2.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldelem_I2, InstrCodesDb.Ldelem_I2_) }, + //{ OpCodes.Ldelem_I4.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldelem_I4, InstrCodesDb.Ldelem_I4_) }, + //{ OpCodes.Ldelem_I8.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldelem_I8, InstrCodesDb.Ldelem_I8_) }, + //{ OpCodes.Ldelem_R4.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldelem_R4, InstrCodesDb.Ldelem_R4_) }, + //{ OpCodes.Ldelem_R8.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldelem_R8, InstrCodesDb.Ldelem_R8_) }, + //{ OpCodes.Ldelem_Ref.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldelem_Ref, InstrCodesDb.Ldelem_Ref_) }, + //{ OpCodes.Ldelem_U1.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldelem_U1, InstrCodesDb.Ldelem_U1_) }, + //{ OpCodes.Ldelem_U2.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldelem_U2, InstrCodesDb.Ldelem_U2_) }, + //{ OpCodes.Ldelem_U4.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldelem_U4, InstrCodesDb.Ldelem_U4_) }, + //{ OpCodes.Ldelema.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldelema, InstrCodesDb.Ldelema_) }, + //{ OpCodes.Ldfld.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldfld, InstrCodesDb.Ldfld_) }, + //{ OpCodes.Ldflda.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldflda, InstrCodesDb.Ldflda_) }, + //{ OpCodes.Ldftn.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldftn, InstrCodesDb.Ldftn_) }, + //{ OpCodes.Ldind_I.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldind_I, InstrCodesDb.Ldind_I_) }, + //{ OpCodes.Ldind_I1.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldind_I1, InstrCodesDb.Ldind_I1_) }, + //{ OpCodes.Ldind_I2.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldind_I2, InstrCodesDb.Ldind_I2_) }, + //{ OpCodes.Ldind_I4.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldind_I4, InstrCodesDb.Ldind_I4_) }, + //{ OpCodes.Ldind_I8.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldind_I8, InstrCodesDb.Ldind_I8_) }, + //{ OpCodes.Ldind_R4.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldind_R4, InstrCodesDb.Ldind_R4_) }, + //{ OpCodes.Ldind_R8.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldind_R8, InstrCodesDb.Ldind_R8_) }, + //{ OpCodes.Ldind_Ref.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldind_Ref, InstrCodesDb.Ldind_Ref_) }, + //{ OpCodes.Ldind_U1.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldind_U1, InstrCodesDb.Ldind_U1_) }, + //{ OpCodes.Ldind_U2.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldind_U2, InstrCodesDb.Ldind_U2_) }, + //{ OpCodes.Ldind_U4.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldind_U4, InstrCodesDb.Ldind_U4_) }, + //{ OpCodes.Ldlen.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldlen, InstrCodesDb.Ldlen_) }, + //{ OpCodes.Ldloc.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldloc, InstrCodesDb.Ldloc_) }, + //{ OpCodes.Ldloc_0.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldloc_0, InstrCodesDb.Ldloc_0_) }, + //{ OpCodes.Ldloc_1.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldloc_1, InstrCodesDb.Ldloc_1_) }, + //{ OpCodes.Ldloc_2.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldloc_2, InstrCodesDb.Ldloc_2_) }, + //{ OpCodes.Ldloc_3.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldloc_3, InstrCodesDb.Ldloc_3_) }, + //{ OpCodes.Ldloc_S.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldloc_S, InstrCodesDb.Ldloc_S_) }, + //{ OpCodes.Ldloca.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldloca, InstrCodesDb.Ldloca_) }, + //{ OpCodes.Ldloca_S.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldloca_S, InstrCodesDb.Ldloca_S_) }, + //{ OpCodes.Ldnull.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldnull, InstrCodesDb.Ldnull_) }, + //{ OpCodes.Ldobj.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldobj, InstrCodesDb.Ldobj_) }, + //{ OpCodes.Ldsfld.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldsfld, InstrCodesDb.Ldsfld_) }, + //{ OpCodes.Ldsflda.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldsflda, InstrCodesDb.Ldsflda_) }, + //{ OpCodes.Ldstr.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldstr, InstrCodesDb.Ldstr_) }, + //{ OpCodes.Ldtoken.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldtoken, InstrCodesDb.Ldtoken_) }, + //{ OpCodes.Ldvirtftn.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ldvirtftn, InstrCodesDb.Ldvirtftn_) }, + //{ OpCodes.Leave.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Leave, InstrCodesDb.Leave_) }, + //{ OpCodes.Leave_S.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Leave_S, InstrCodesDb.Leave_S_) }, + //{ OpCodes.Localloc.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Localloc, InstrCodesDb.Localloc_) }, + //{ OpCodes.Mkrefany.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Mkrefany, InstrCodesDb.Mkrefany_) }, + { OpCodes.Mul.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Mul, InstrCodesDb.Mul_) }, + { OpCodes.Mul_Ovf.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Mul_Ovf, InstrCodesDb.Mul_ovf_) }, + { OpCodes.Mul_Ovf_Un.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Mul_Ovf_Un, InstrCodesDb.Mul_ovf_un_) }, + //{ OpCodes.Neg.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Neg, InstrCodesDb.Neg_) }, + //{ OpCodes.Newarr.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Newarr, InstrCodesDb.Newarr_) }, + { OpCodes.Newobj.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Newobj, InstrCodesDb.Newobj_) }, + //{ OpCodes.Nop.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Nop, InstrCodesDb.Nop_) }, + { OpCodes.Not.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Not, InstrCodesDb.Not_) }, + { OpCodes.Or.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Or, InstrCodesDb.Or_) }, + //{ OpCodes.Pop.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Pop, InstrCodesDb.Pop_) }, + //{ OpCodes.Prefix1.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Prefix1, InstrCodesDb.Prefix1_) }, + //{ OpCodes.Prefix2.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Prefix2, InstrCodesDb.Prefix2_) }, + //{ OpCodes.Prefix3.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Prefix3, InstrCodesDb.Prefix3_) }, + //{ OpCodes.Prefix4.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Prefix4, InstrCodesDb.Prefix4_) }, + //{ OpCodes.Prefix5.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Prefix5, InstrCodesDb.Prefix5_) }, + //{ OpCodes.Prefix6.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Prefix6, InstrCodesDb.Prefix6_) }, + //{ OpCodes.Prefix7.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Prefix7, InstrCodesDb.Prefix7_) }, + //{ OpCodes.Prefixref.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Prefixref, InstrCodesDb.Prefixref_) }, + //{ OpCodes.Readonly.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Readonly, InstrCodesDb.Readonly_) }, + //{ OpCodes.Refanytype.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Refanytype, InstrCodesDb.Refanytype_) }, + //{ OpCodes.Refanyval.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Refanyval, InstrCodesDb.Refanyval_) }, + { OpCodes.Rem.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Rem, InstrCodesDb.Rem_) }, + { OpCodes.Rem_Un.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Rem_Un, InstrCodesDb.Rem_un_) }, + { OpCodes.Ret.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Ret, InstrCodesDb.Ret_) }, + //{ OpCodes.Rethrow.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Rethrow, InstrCodesDb.Rethrow_) }, + { OpCodes.Shl.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Shl, InstrCodesDb.Shl_) }, + { OpCodes.Shr.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Shr, InstrCodesDb.Shr_) }, + { OpCodes.Shr_Un.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Shr_Un, InstrCodesDb.Shr_un_) }, + //{ OpCodes.Sizeof.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Sizeof, InstrCodesDb.Sizeof_) }, + //{ OpCodes.Starg.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Starg, InstrCodesDb.Starg_) }, + //{ OpCodes.Starg_S.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Starg_S, InstrCodesDb.Starg_S_) }, + //{ OpCodes.Stelem.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stelem, InstrCodesDb.Stelem_) }, + //{ OpCodes.Stelem_I.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stelem_I, InstrCodesDb.Stelem_I_) }, + //{ OpCodes.Stelem_I1.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stelem_I1, InstrCodesDb.Stelem_I1_) }, + //{ OpCodes.Stelem_I2.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stelem_I2, InstrCodesDb.Stelem_i2_) }, + //{ OpCodes.Stelem_I4.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stelem_I4, InstrCodesDb.Stelem_I4_) }, + //{ OpCodes.Stelem_I8.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stelem_I8, InstrCodesDb.Stelem_I8_) }, + //{ OpCodes.Stelem_R4.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stelem_R4, InstrCodesDb.Stelem_R4_) }, + //{ OpCodes.Stelem_R8.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stelem_R8, InstrCodesDb.Stelem_R8_) }, + //{ OpCodes.Stelem_Ref.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stelem_Ref, InstrCodesDb.Stelem_Ref_) }, + //{ OpCodes.Stfld.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stfld, InstrCodesDb.Stfld_) }, + //{ OpCodes.Stind_I.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stind_I, InstrCodesDb.Stind_I_) }, + //{ OpCodes.Stind_I1.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stind_I1, InstrCodesDb.Stind_I1_) }, + //{ OpCodes.Stind_I2.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stind_I2, InstrCodesDb.Stind_I2_) }, + //{ OpCodes.Stind_I4.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stind_I4, InstrCodesDb.Stind_I4_) }, + //{ OpCodes.Stind_I8.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stind_I8, InstrCodesDb.Stind_I8_) }, + //{ OpCodes.Stind_R4.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stind_R4, InstrCodesDb.Stind_R4_) }, + //{ OpCodes.Stind_R8.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stind_R8, InstrCodesDb.Stind_R8_) }, + //{ OpCodes.Stind_Ref.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stind_Ref, InstrCodesDb.Stind_Ref_) }, + //{ OpCodes.Stloc.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stloc, InstrCodesDb.Stloc_) }, + //{ OpCodes.Stloc_0.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stloc_0, InstrCodesDb.Stloc_0_) }, + //{ OpCodes.Stloc_1.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stloc_1, InstrCodesDb.Stloc_1_) }, + //{ OpCodes.Stloc_2.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stloc_2, InstrCodesDb.Stloc_2_) }, + //{ OpCodes.Stloc_3.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stloc_3, InstrCodesDb.Stloc_3_) }, + //{ OpCodes.Stloc_S.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stloc_S, InstrCodesDb.Stloc_S_) }, + //{ OpCodes.Stobj.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stobj, InstrCodesDb.Stobj_) }, + //{ OpCodes.Stsfld.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Stsfld, InstrCodesDb.Stsfld_) }, + { OpCodes.Sub.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Sub, InstrCodesDb.Sub_) }, + { OpCodes.Sub_Ovf.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Sub_Ovf, InstrCodesDb.Sub_ovf_) }, + { OpCodes.Sub_Ovf_Un.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Sub_Ovf_Un, InstrCodesDb.Sub_ovf_un_) }, + //{ OpCodes.Switch.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Switch, InstrCodesDb.Switch_) }, + //{ OpCodes.Tailcall.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Tailcall, InstrCodesDb.Tailcall_) }, + //{ OpCodes.Throw.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Throw, InstrCodesDb.Throw_) }, + //{ OpCodes.Unaligned.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Unaligned, InstrCodesDb.Unaligned_) }, + //{ OpCodes.Unbox.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Unbox, InstrCodesDb.Unbox_) }, + //{ OpCodes.Unbox_Any.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Unbox_Any, InstrCodesDb.Unbox_Any_) }, + //{ OpCodes.Volatile.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Volatile, InstrCodesDb.Volatile_) }, + { OpCodes.Xor.Value, new KeyValuePair<OpCode, VmInstrInfo>(OpCodes.Xor, InstrCodesDb.Xor_) }, + }; + #endregion + public override Stream CreateVmStream(Type rt, ParameterInfo[] pi, Type[] locals, byte [] ilBytes /*GetIlBytes(src)*/) + { + var ret = new MemoryStream(); + var wr = new BinaryWriter(ret); + var fwdTypeDefs = new Dictionary<Type, int>(); + var fwdTypeRefs = new Dictionary<int, Type>(); + var fwdMethodTokenDefs = new Dictionary<UInt32, int>(); + var fwdMethodTokenRefs = new Dictionary<long, UInt32>(); + var deferredBrTargets = new Dictionary<long, UInt32>(); + var srcToDstInstrPositions = new Dictionary<long, UInt32>(); + wr.Write(0); // ClassId + wr.Flush(); + const int dummy = 0x55555555; + fwdTypeDefs.Add(rt, dummy); + fwdTypeRefs.Add((int)ret.Position, rt); + wr.Write(dummy); // ReturnTypeId fwd ref + wr.Write((ushort)0); // LocalVarTypes + wr.Write((byte)2); // Flags - static + wr.Write((byte)0); // Name + var pars = pi; + wr.Write((ushort)pars.Length); // ArgsTypeToOutput + foreach (var parameterInfo in pars) + { + if (!fwdTypeDefs.ContainsKey(parameterInfo.ParameterType)) + fwdTypeDefs.Add(parameterInfo.ParameterType, dummy); + fwdTypeRefs.Add((int)ret.Position, parameterInfo.ParameterType); + wr.Write(dummy); // parTypeId fwd ref + wr.Write(false); + } + wr.Write((ushort)locals.Length); // LocalVarTypes + foreach (var lt in locals) + { + if (!fwdTypeDefs.ContainsKey(lt)) + fwdTypeDefs.Add(lt, dummy); + fwdTypeRefs.Add((int)ret.Position, lt); + wr.Write(dummy); // parTypeId fwd ref + } + + var methodLengthPos = ret.Position; + wr.Write(dummy); // methodLength + using (var sr = new BinaryReader(new MemoryStream(ilBytes))) + { + while (sr.BaseStream.Position < sr.BaseStream.Length) + { + srcToDstInstrPositions[sr.BaseStream.Position] = (uint)ret.Position; + short ilByte = sr.ReadByte(); + if (ilByte == 0xFE) + ilByte = (short)((ilByte << 8) | sr.ReadByte()); + Assert.IsTrue(IlToVmInstrInfo.ContainsKey(ilByte), "Extend IlToVmInstrInfo with {0:X} or use short jump", ilByte); + var vmInstrInfo = IlToVmInstrInfo[ilByte]; + var id = vmInstrInfo.Value.Id; + wr.Write((ushort)(id >> 16)); + wr.Write((ushort)(id & 0xFFFF)); + wr.Flush(); + ulong operand = 0; + switch (vmInstrInfo.Key.OperandType) + { + case OperandType.InlineNone: + break; + case OperandType.InlineI8: + case OperandType.InlineR: + operand = sr.ReadUInt64(); + break; + case OperandType.InlineVar: + operand = sr.ReadUInt16(); + break; + case OperandType.ShortInlineBrTarget: + case OperandType.ShortInlineI: + case OperandType.ShortInlineVar: + operand = sr.ReadByte(); + break; + default: + operand = sr.ReadUInt32(); + break; + } + if (vmInstrInfo.Key.OperandType == OperandType.ShortInlineBrTarget) + { + deferredBrTargets[wr.BaseStream.Position] = (uint)sr.BaseStream.Position + (uint)operand; + } + if (vmInstrInfo.Key.Value == OpCodes.Newobj.Value || vmInstrInfo.Key.Value == OpCodes.Call.Value) + { + var token = (uint)operand; + if (!fwdMethodTokenDefs.ContainsKey(token)) + fwdMethodTokenDefs.Add(token, dummy); + fwdMethodTokenRefs[wr.BaseStream.Position] = token; + } + switch (vmInstrInfo.Value.OperandType) + { + case VmOperandType.Ot11Nope: + break; + case VmOperandType.Ot2Byte: + case VmOperandType.Ot6SByte: + case VmOperandType.Ot8Byte: + wr.Write((byte)operand); + break; + case VmOperandType.Ot1UShort: + case VmOperandType.Ot3UShort: + wr.Write((ushort)operand); + break; + case VmOperandType.Ot0UInt: + case VmOperandType.Ot12Int: + case VmOperandType.Ot5Int: + case VmOperandType.Ot10Float: + wr.Write((uint)operand); + break; + case VmOperandType.Ot7Long: + case VmOperandType.Ot4Double: + wr.Write(operand); + break; + default: + throw new InvalidDataException("OperandType"); + } + } + ret.Position = methodLengthPos; + wr.Write((int)(ret.Length - methodLengthPos - 4)); + wr.Flush(); + ret.Position = ret.Length; + foreach (var t in fwdTypeDefs.Keys.ToArray()) + { + fwdTypeDefs[t] = (int)ret.Position; + wr.Write(true); + wr.Write((byte)0); + wr.Write(-1); + wr.Write(-1); + wr.Write(false); + // ReSharper disable once AssignNullToNotNullAttribute + wr.Write(t.AssemblyQualifiedName); + wr.Write(false); + wr.Write((ushort)0); + wr.Flush(); + } + foreach (var t in fwdMethodTokenDefs.Keys.ToArray()) + { + fwdMethodTokenDefs[t] = (int)ret.Position; + wr.Write((byte)0); + wr.Write(t); + wr.Flush(); + } + foreach (var r in fwdTypeRefs) + { + ret.Position = r.Key; + wr.Write(fwdTypeDefs[r.Value]); + wr.Flush(); + } + foreach (var t in fwdMethodTokenRefs) + { + ret.Position = t.Key; + wr.Write((ushort)(fwdMethodTokenDefs[t.Value]>>16)); + wr.Write((ushort)fwdMethodTokenDefs[t.Value]); + wr.Flush(); + } + foreach (var r in deferredBrTargets) + { + ret.Position = r.Key; + var srcPos = r.Value; + wr.Write(srcToDstInstrPositions[srcPos] - (uint)methodLengthPos - 4); + wr.Flush(); + } + ret.Position = 0; + return ret; + } + } + public override object Invoke(object[] parameters, Stream vmStream) + { + var vmStreamWrapper = new VmStreamWrapper(vmStream, VmExecutor.VmXorKey()); + var callees = new object[] + { + Assembly.GetCallingAssembly() + }; + var vm = new VmExecutor(InstrCodesDb, vmStreamWrapper); + vm.Seek(0, vmStreamWrapper, null); + var vmRet = vm.Invoke(parameters, null, null, callees); + return vmRet; + } + } + + internal static class ExtendedEcma335 + { + internal static object AsStackedValue(object v, bool signedComparison) // как это значение будет лежать на стеке + { + Type t = v.GetType(); + if (IsFloatingType(t)) + return v; + //остальное приводится к Int32 или Int64 + if (t.IsEnum) t = t.GetEnumUnderlyingType(); + if (t == typeof (byte)) return signedComparison ? (object) (Int32) (byte) v : (UInt32) (byte)v; + if (t == typeof (sbyte)) return signedComparison ? (object) (Int32) (sbyte) v : (UInt32) (sbyte)v; + if (t == typeof (short)) return signedComparison ? (object) (Int32) (short) v : (UInt32) (short)v; + if (t == typeof (ushort)) return signedComparison ? (object) (Int32) (ushort)v : (UInt32)(ushort) v; + if (t == typeof (Char)) return signedComparison ? (object) (Int32) (Char)v : (UInt32) (Char) v; + if (t == typeof (Int32)) return signedComparison ? (object) (Int32) v : (UInt32) (Int32)v; + if (t == typeof (UInt32)) return signedComparison ? (object) (Int32) (UInt32) v : (UInt32)v; + if (t == typeof(Int64)) return signedComparison ? (object) (Int64)v : (UInt64) (Int64)v; + if (t == typeof (UInt64)) return signedComparison ? (object) (Int64) (UInt64) v : (UInt64)v; + if (t == typeof(bool)) return signedComparison ? (object) ((bool)v ? 1 : 0) : (UInt32) ((bool)v ? 1 : 0); + if (t == typeof(IntPtr)) + { + if (IntPtr.Size == 4) + return signedComparison ? (object)((IntPtr)v).ToInt32() : (UInt32)((IntPtr)v).ToInt32(); + return signedComparison ? (object)((IntPtr)v).ToInt64() : (UInt64)((IntPtr)v).ToInt64(); + } + if (t == typeof(UIntPtr)) + { + if (UIntPtr.Size == 4) + return signedComparison ? (object)(Int32)((UIntPtr)v).ToUInt32() : ((UIntPtr)v).ToUInt32(); + return signedComparison ? (object)(Int64)((UIntPtr)v).ToUInt64() : ((UIntPtr)v).ToUInt64(); + } + return v; + } + + [SuppressMessage("ReSharper", "RedundantCast")] + internal static bool Check(KeyValuePair<OpCode, UnitTestCombine.CodeTemplate> op, object[] parameters, object vmRet) + { + try + { + if (parameters.Length == 2 && op.Value == UnitTestCombine.CodeTemplate.TwoOpAny && + (op.Key.Value == OpCodes.Shl.Value || op.Key.Value == OpCodes.Shr.Value || + op.Key.Value == OpCodes.Shr_Un.Value)) + { + var t0 = parameters[0].GetType(); + var t1 = parameters[1].GetType(); + if (t0 == typeof (object) || t1 == typeof (object)) + return true; // TODO понять бы, почему нет совпадения с фреймфорком + if (IsFloatingType(t0) || IsFloatingType(t1)) + return true; // в зависимости от разрядности фреймворк дурит по-разному + bool sign = op.Key.Value != OpCodes.Shr_Un.Value; + var commonType = UnitTestCombine.CompatibleType(t0, t1, sign); + if (commonType == typeof (Int64) || commonType == typeof (UInt64)) + { + if (sign) + { + var p0 = Convert.ToInt64(AsStackedValue(parameters[0], true)); + var p1 = Convert.ToInt64(AsStackedValue(parameters[1], true)); + return Convert.ToInt64(AsStackedValue(vmRet, true)) == + ((op.Key.Value == OpCodes.Shl.Value) ? (p1 << (int)p0) : (p1 >> (int)p0)); + } + else + { + var p0 = Convert.ToUInt64(AsStackedValue(parameters[0], false)); + var p1 = Convert.ToUInt64(AsStackedValue(parameters[1], false)); + return Convert.ToUInt64(AsStackedValue(vmRet, false)) == (p1 >> (int) p0); + } + } + } + if (parameters.Length == 2 && op.Value == UnitTestCombine.CodeTemplate.TwoOpAny && + (op.Key.Value == OpCodes.And.Value || op.Key.Value == OpCodes.Or.Value || op.Key.Value == OpCodes.Xor.Value)) + { + var t0 = parameters[0].GetType(); + var t1 = parameters[1].GetType(); + if (t0 == typeof (object) || t1 == typeof (object)) + return true; // TODO понять бы, почему нет совпадения с фреймфорком + if (IntPtr.Size == 8) + { + if (t0 == typeof (double) || t1 == typeof (double)) + // ReSharper disable once CompareOfFloatsByEqualityOperator + return Convert.ToDouble(vmRet) == ((4 == IntPtr.Size) ? Double.NaN : (double) 0); + if (t0 == typeof (float) || t1 == typeof (float)) + // ReSharper disable once CompareOfFloatsByEqualityOperator + return Convert.ToSingle(vmRet) == ((4 == IntPtr.Size) ? Single.NaN : (float) 0); + } + //x64, как более точный в фреймворке, не даёт сюда срабатываний + if (IntPtr.Size == 4 && t0 != t1) + { + var p0 = Convert.ToInt64(AsStackedValue(parameters[0], true)); + var p1 = Convert.ToInt64(AsStackedValue(parameters[1], true)); + Int64 check = 0; + if (op.Key.Value == OpCodes.And.Value) check = p0 & p1; + if (op.Key.Value == OpCodes.Or.Value) check = p0 | p1; + if (op.Key.Value == OpCodes.Xor.Value) check = p0 ^ p1; + return Convert.ToInt64(AsStackedValue(vmRet, true)) == check; + } + } + bool bAdd = op.Key.Value == OpCodes.Add.Value || op.Key.Value == OpCodes.Add_Ovf.Value || + op.Key.Value == OpCodes.Add_Ovf_Un.Value; + bool bSub = op.Key.Value == OpCodes.Sub.Value || op.Key.Value == OpCodes.Sub_Ovf.Value || + op.Key.Value == OpCodes.Sub_Ovf_Un.Value; + bool bMul = op.Key.Value == OpCodes.Mul.Value || op.Key.Value == OpCodes.Mul_Ovf.Value || + op.Key.Value == OpCodes.Mul_Ovf_Un.Value; + bool bDiv = op.Key.Value == OpCodes.Div.Value || op.Key.Value == OpCodes.Div_Un.Value; + bool bRem = op.Key.Value == OpCodes.Rem.Value || op.Key.Value == OpCodes.Rem_Un.Value; + if (parameters.Length == 2 && op.Value == UnitTestCombine.CodeTemplate.TwoOpAny && (bAdd || bSub || bMul || bDiv || bRem)) + { + var t0 = parameters[0].GetType(); + var t1 = parameters[1].GetType(); + if ((t0 == typeof (object) || t1 == typeof (object)) && (!(vmRet is Exception) || (op.Key.Value == OpCodes.Mul_Ovf.Value) || (op.Key.Value == OpCodes.Mul_Ovf_Un.Value) || (op.Key.Value == OpCodes.Sub_Ovf_Un.Value))) + return true; // TODO понять бы, почему нет совпадения с фреймфорком + // баг фреймворка в x64 Mul_Ovf_Un для плавающих + if (t0 == t1 && !(IntPtr.Size == 8 && op.Key.Value == OpCodes.Mul_Ovf_Un.Value && IsFloatingType(t0) && t0==t1)) return false; + bool sign = op.Key.Value != OpCodes.Add_Ovf_Un.Value && op.Key.Value != OpCodes.Sub_Ovf_Un.Value && op.Key.Value != OpCodes.Mul_Ovf_Un.Value && op.Key.Value != OpCodes.Div_Un.Value && op.Key.Value != OpCodes.Rem_Un.Value; + var commonType = UnitTestCombine.CompatibleType(t0, t1, sign); + if (commonType == typeof (Int64) || commonType == typeof (UInt64)) + { + if (sign) + { + var p0 = Convert.ToInt64(AsStackedValue(parameters[0], true)); + var p1 = Convert.ToInt64(AsStackedValue(parameters[1], true)); + if (vmRet is OverflowException && (op.Key.Value == OpCodes.Add_Ovf.Value || op.Key.Value == OpCodes.Sub_Ovf.Value || op.Key.Value == OpCodes.Mul_Ovf.Value)) + { + decimal res = bAdd ? ((decimal)p0 + (decimal)p1) : bSub ? ((decimal)p1 - (decimal)p0) : ((decimal)p1 * (decimal)p0); + if (commonType == typeof(Int64)) + return res > (decimal)Int64.MaxValue || res < (decimal)Int64.MinValue; + if (commonType == typeof(UInt64)) + return res > (decimal)UInt64.MaxValue || res < 0; + } + else + { + if (p0 == 0 && (bDiv || bRem)) return vmRet is DivideByZeroException; + try + { + return (bAdd ? (p0 + p1) : bSub ? (p1 - p0) : bMul ? (p1 * p0) : bDiv ? (p1 / p0) : (p1 % p0)) == Convert.ToInt64(AsStackedValue(vmRet, true)); + } + catch (Exception e) + { + return e.GetType() == vmRet.GetType(); + } + } + } else + { + var p0 = Convert.ToUInt64(AsStackedValue(parameters[0], false)); + var p1 = Convert.ToUInt64(AsStackedValue(parameters[1], false)); + if (vmRet is OverflowException && op.Key.Value == OpCodes.Sub_Ovf_Un.Value && 4 == IntPtr.Size) + { + decimal res = (decimal)p1 - (decimal)p0; + if (commonType == typeof(UInt64)) + return res > (decimal)UInt64.MaxValue || res < 0; + } + else + { + if (p0 == 0 && (bDiv || bRem)) return vmRet is DivideByZeroException; + return Convert.ToUInt64(AsStackedValue(vmRet, false)) == (bAdd ? (p0 + p1) : bSub ? (p1 - p0) : bMul ? (p1 * p0) : bDiv ? (p1 / p0) : (p1 % p0)); + } + } + } else if (commonType == typeof(float)) + { + var p0 = Convert.ToSingle(AsStackedValue(parameters[0], sign)); + var p1 = Convert.ToSingle(AsStackedValue(parameters[1], sign)); + // ReSharper disable once CompareOfFloatsByEqualityOperator + if (p0 == 0 && (bDiv || bRem)) return vmRet is DivideByZeroException; + var vm = Convert.ToSingle(AsStackedValue(vmRet, sign)); + if (float.IsNaN(p0) || float.IsNaN(p1) || float.IsNaN(vm)) return true; + // ReSharper disable once RedundantCast + // ReSharper disable once CompareOfFloatsByEqualityOperator + return vm == (float)(bAdd ? (p0 + p1) : bSub ? (p1 - p0) : bMul ? (p1 * p0) : bDiv ? (p1 / p0) : (p1 % p0)); + } else if (commonType == typeof(double)) + { + var p0 = Convert.ToDouble(AsStackedValue(parameters[0], sign)); + var p1 = Convert.ToDouble(AsStackedValue(parameters[1], sign)); + // ReSharper disable once CompareOfFloatsByEqualityOperator + if (p0 == 0 && (bDiv || bRem)) return vmRet is DivideByZeroException; + var vm = Convert.ToDouble(AsStackedValue(vmRet, sign)); + if (double.IsNaN(p0) || double.IsNaN(p1) || double.IsNaN(vm)) return true; + // ReSharper disable once CompareOfFloatsByEqualityOperator + return vm == (bAdd ? (p0 + p1) : bSub ? (p1 - p0) : bMul ? (p1 * p0) : bDiv ? (p1 / p0) : (p1 % p0)); + } + } + if (parameters.Length == 1 && op.Value == UnitTestCombine.CodeTemplate.SingleOpAny && op.Key.Value == OpCodes.Conv_U.Value) + { + if (IsFloatingType(parameters[0].GetType()) && !(vmRet is Exception)) + { + // Framework использует мусор, мы возврвщаем 0 + // ReSharper disable once CompareOfFloatsByEqualityOperator + return Convert.ToDouble(vmRet) == 0.0; + } + } + if (parameters.Length == 1 && op.Value == UnitTestCombine.CodeTemplate.SingleOpAny && op.Key.Value == OpCodes.Ckfinite.Value) + { + if (!IsFloatingType(parameters[0].GetType()) && !(vmRet is Exception)) + { + double d = Double.NaN; + if (parameters[0] is IConvertible) + { + d = Convert.ToDouble(AsStackedValue(parameters[0], true)); + } + return Convert.ToDouble(vmRet).Equals(d); + } + } + if (parameters.Length == 2 && (op.Value == UnitTestCombine.CodeTemplate.BranchTwoOpBool || op.Value == UnitTestCombine.CodeTemplate.TwoOpBool)) + { + var signedComparison = (op.Key.Value == OpCodes.Bgt_S.Value || op.Key.Value == OpCodes.Ble_S.Value || + op.Key.Value == OpCodes.Bge_S.Value || op.Key.Value == OpCodes.Blt_S.Value || op.Key.Value == OpCodes.Beq_S.Value || + op.Key.Value == OpCodes.Cgt.Value || op.Key.Value == OpCodes.Clt.Value || op.Key.Value == OpCodes.Ceq.Value); + var unsignedUnorderedComparison = (op.Key.Value == OpCodes.Bgt_Un_S.Value || op.Key.Value == OpCodes.Ble_Un_S.Value || + op.Key.Value == OpCodes.Bge_Un_S.Value || op.Key.Value == OpCodes.Blt_Un_S.Value || + op.Key.Value == OpCodes.Cgt_Un.Value || op.Key.Value == OpCodes.Clt_Un.Value || op.Key.Value == OpCodes.Bne_Un_S.Value); + if (signedComparison || unsignedUnorderedComparison) + { + var isFloat = parameters.Select(o => IsFloatingType(o.GetType())).ToArray(); + // разрешаем сравнивать такие типы + if (isFloat[0] != isFloat[1]) + { + //F and int32/64 + var vStacked = parameters.Select(o => AsStackedValue(o, true)).ToArray(); + if (vStacked.Any(o => !(o is IConvertible))) + { + return (bool)vmRet == (op.Key.Value == OpCodes.Bne_Un_S.Value); + } + double a = Convert.ToDouble(vStacked[1]), b = Convert.ToDouble(vStacked[0]); + return Compare(op, vmRet, a, b, unsignedUnorderedComparison); + } + else if (isFloat.All(o => o == false)) + { + var vStacked = parameters.Select(o => AsStackedValue(o, signedComparison)).ToArray(); + if (vStacked.Any(o => !(o is IConvertible))) + { + return (bool)vmRet == false; + } + var vStackSize = vStacked.Select(o => Marshal.SizeOf(o.GetType())).ToArray(); + if (vStackSize[0] != vStackSize[1]) + { + //32 bit and 64 bit ints + if (signedComparison) + { + Int64 a = (vStackSize[1] == 8) ? (Int64)vStacked[1] : (Int32)vStacked[1]; + Int64 b = (vStackSize[0] == 8) ? (Int64)vStacked[0] : (Int32)vStacked[0]; + return Compare(op, vmRet, a, b); + } + else + { + UInt64 a = (vStackSize[1] == 8) ? (UInt64)vStacked[1] : (UInt32)vStacked[1]; + UInt64 b = (vStackSize[0] == 8) ? (UInt64)vStacked[0] : (UInt32)vStacked[0]; + return Compare(op, vmRet, a, b); + } + } + } + } + } + } + catch (Exception exc) + { + Console.Error.WriteLine(exc); + } + + return false; + } + + private static bool Compare(KeyValuePair<OpCode, UnitTestCombine.CodeTemplate> op, object vmRet, Double a, Double b, bool unordered) + { + if (unordered && (Double.IsNaN(a) || Double.IsNaN(b))) + { + return true; + } + if (op.Key.Value == OpCodes.Bgt_S.Value || op.Key.Value == OpCodes.Bgt_Un_S.Value || op.Key.Value == OpCodes.Cgt.Value || op.Key.Value == OpCodes.Cgt_Un.Value) + return ((a > b) == (bool)vmRet); + if (op.Key.Value == OpCodes.Ble_S.Value || op.Key.Value == OpCodes.Ble_Un_S.Value) + return ((a <= b) == (bool)vmRet); + if (op.Key.Value == OpCodes.Bge_S.Value || op.Key.Value == OpCodes.Bge_Un_S.Value) + return ((a >= b) == (bool)vmRet); + if (op.Key.Value == OpCodes.Blt_S.Value || op.Key.Value == OpCodes.Blt_Un_S.Value || op.Key.Value == OpCodes.Clt.Value || op.Key.Value == OpCodes.Clt_Un.Value) + return ((a < b) == (bool)vmRet); + if (op.Key.Value == OpCodes.Ceq.Value || op.Key.Value == OpCodes.Beq_S.Value) + // ReSharper disable once CompareOfFloatsByEqualityOperator + return ((a == b) == (bool)vmRet); + if (op.Key.Value == OpCodes.Bne_Un_S.Value) + // ReSharper disable once CompareOfFloatsByEqualityOperator + return ((a != b) == (bool)vmRet); + Assert.Fail("Bad op for Compare"); + return false; + } + + private static bool Compare<T>(KeyValuePair<OpCode, UnitTestCombine.CodeTemplate> op, object vmRet, T a, T b) where T : IComparable<T> + { + if (op.Key.Value == OpCodes.Bgt_S.Value || op.Key.Value == OpCodes.Bgt_Un_S.Value || op.Key.Value == OpCodes.Cgt.Value || op.Key.Value == OpCodes.Cgt_Un.Value) + return ((a.CompareTo(b) > 0) == (bool)vmRet); + if (op.Key.Value == OpCodes.Ble_S.Value || op.Key.Value == OpCodes.Ble_Un_S.Value) + return ((a.CompareTo(b) <= 0) == (bool)vmRet); + if (op.Key.Value == OpCodes.Bge_S.Value || op.Key.Value == OpCodes.Bge_Un_S.Value) + return ((a.CompareTo(b) >= 0) == (bool)vmRet); + if (op.Key.Value == OpCodes.Blt_S.Value || op.Key.Value == OpCodes.Blt_Un_S.Value || op.Key.Value == OpCodes.Clt.Value || op.Key.Value == OpCodes.Clt_Un.Value) + return ((a.CompareTo(b) < 0) == (bool)vmRet); + if (op.Key.Value == OpCodes.Ceq.Value || op.Key.Value == OpCodes.Beq_S.Value) + return (a.Equals(b) == (bool)vmRet); + if (op.Key.Value == OpCodes.Bne_Un_S.Value) + return ((!a.Equals(b)) == (bool)vmRet); + Assert.Fail("Bad op for Compare"); + return false; + } + + private static bool IsFloatingType(Type t) + { + return t == typeof (Single) || t == typeof (Double); + } + } +} diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/UnitTestProject.csproj b/runtime/VMProtect.Runtime/Tests/UnitTestProject/UnitTestProject.csproj new file mode 100644 index 0000000..c04c1ef --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/UnitTestProject.csproj @@ -0,0 +1,159 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{85318BED-28D8-4B31-A7BA-9ED7882D11FC}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>UnitTestProject</RootNamespace> + <AssemblyName>UnitTestProject</AssemblyName> + <TargetFrameworkVersion>v4.8</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion> + <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> + <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath> + <IsCodedUITest>False</IsCodedUITest> + <TestProjectType>UnitTest</TestProjectType> + <TargetFrameworkProfile /> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <PlatformTarget>AnyCPU</PlatformTarget> + <Prefer32Bit>false</Prefer32Bit> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <Prefer32Bit>false</Prefer32Bit> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="System.Core"> + <RequiredTargetFramework>3.5</RequiredTargetFramework> + </Reference> + <Reference Include="System.Web" /> + <Reference Include="System.Windows.Forms" /> + </ItemGroup> + <Choose> + <When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'"> + <ItemGroup> + <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" /> + </ItemGroup> + </When> + <Otherwise> + <ItemGroup> + <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" /> + </ItemGroup> + </Otherwise> + </Choose> + <ItemGroup> + <Compile Include="..\..\Crypto.cs"> + <Link>CipherRC5.cs</Link> + </Compile> + <Compile Include="..\..\Core.cs"> + <Link>Core.cs</Link> + </Compile> + <Compile Include="..\..\CpuId.cs"> + <Link>CpuId.cs</Link> + </Compile> + <Compile Include="..\..\Faces.cs"> + <Link>Faces.cs</Link> + </Compile> + <Compile Include="..\..\HardwareID.cs"> + <Link>HardwareID.cs</Link> + </Compile> + <Compile Include="..\..\LicensingManager.cs"> + <Link>LicensingManager.cs</Link> + </Compile> + <Compile Include="..\..\Loader.cs"> + <Link>Loader.cs</Link> + </Compile> + <Compile Include="..\..\LzmaDecoder.cs"> + <Link>LzmaDecoder.cs</Link> + </Compile> + <Compile Include="..\..\Numerics\BigInteger.cs"> + <Link>Numerics\BigInteger.cs</Link> + </Compile> + <Compile Include="..\..\Numerics\BigIntegerBuilder.cs"> + <Link>Numerics\BigIntegerBuilder.cs</Link> + </Compile> + <Compile Include="..\..\Numerics\NumericHelpers.cs"> + <Link>Numerics\NumericHelpers.cs</Link> + </Compile> + <Compile Include="..\..\StringManager.cs"> + <Link>StringManager.cs</Link> + </Compile> + <Compile Include="..\..\VirtualMachine.cs"> + <Link>VirtualMachine.cs</Link> + </Compile> + <Compile Include="..\..\Win32.cs"> + <Link>Win32.cs</Link> + </Compile> + <Compile Include="LicensingManagerTests.cs" /> + <Compile Include="LoaderTests.cs" /> + <Compile Include="MsilToVmTestCompiler.cs" /> + <Compile Include="RefVm\ElementedTypeHelper.cs" /> + <Compile Include="RefVm\MyBuffer.cs" /> + <Compile Include="RefVm\MyBufferReader.cs" /> + <Compile Include="RefVm\MyCollection.cs" /> + <Compile Include="RefVm\SdMetadataTokens.cs" /> + <Compile Include="RefVm\SdTemplateStuff.cs" /> + <Compile Include="RefVm\SimpleTypeHelper.cs" /> + <Compile Include="RefVm\StringDecryptor.cs" /> + <Compile Include="RefVm\TypeCompatibility.cs" /> + <Compile Include="RefVm\VariantBase.cs" /> + <Compile Include="RefVm\VariantFactory.cs" /> + <Compile Include="RefVm\VmExecutor.cs" /> + <Compile Include="RefVm\VmInstrCodesDb.cs" /> + <Compile Include="RefVm\VmMethodHeader.cs" /> + <Compile Include="RefVm\VmPosParser.cs" /> + <Compile Include="RefVm\VmStreamWrapper.cs" /> + <Compile Include="UnitTest1.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="UnitTestCombine.cs" /> + </ItemGroup> + <ItemGroup> + <WCFMetadata Include="Service References\" /> + </ItemGroup> + <Choose> + <When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'"> + <ItemGroup> + <Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <Private>False</Private> + </Reference> + <Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <Private>False</Private> + </Reference> + <Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <Private>False</Private> + </Reference> + <Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <Private>False</Private> + </Reference> + </ItemGroup> + </When> + </Choose> + <Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" /> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/runtime/VMProtect.Runtime/Tests/UnitTestProject/UnitTestProject.csproj.bak b/runtime/VMProtect.Runtime/Tests/UnitTestProject/UnitTestProject.csproj.bak new file mode 100644 index 0000000..b5bdc24 --- /dev/null +++ b/runtime/VMProtect.Runtime/Tests/UnitTestProject/UnitTestProject.csproj.bak @@ -0,0 +1,133 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{85318BED-28D8-4B31-A7BA-9ED7882D11FC}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>UnitTestProject</RootNamespace> + <AssemblyName>UnitTestProject</AssemblyName> + <TargetFrameworkVersion>v4.6</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion> + <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> + <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath> + <IsCodedUITest>False</IsCodedUITest> + <TestProjectType>UnitTest</TestProjectType> + <TargetFrameworkProfile /> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <PlatformTarget>AnyCPU</PlatformTarget> + <Prefer32Bit>false</Prefer32Bit> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <Prefer32Bit>false</Prefer32Bit> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="System.Core"> + <RequiredTargetFramework>3.5</RequiredTargetFramework> + </Reference> + <Reference Include="System.Windows.Forms" /> + </ItemGroup> + <Choose> + <When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'"> + <ItemGroup> + <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" /> + </ItemGroup> + </When> + <Otherwise> + <ItemGroup> + <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" /> + </ItemGroup> + </Otherwise> + </Choose> + <ItemGroup> + <Compile Include="..\..\CipherRC5.cs"> + <Link>CipherRC5.cs</Link> + </Compile> + <Compile Include="..\..\Core.cs"> + <Link>Core.cs</Link> + </Compile> + <Compile Include="..\..\CpuId.cs"> + <Link>CpuId.cs</Link> + </Compile> + <Compile Include="..\..\CRC32.cs"> + <Link>CRC32.cs</Link> + </Compile> + <Compile Include="..\..\Faces.cs"> + <Link>Faces.cs</Link> + </Compile> + <Compile Include="..\..\HardwareID.cs"> + <Link>HardwareID.cs</Link> + </Compile> + <Compile Include="..\..\LicensingManager.cs"> + <Link>LicensingManager.cs</Link> + </Compile> + <Compile Include="..\..\Numerics\BigInteger.cs"> + <Link>Numerics\BigInteger.cs</Link> + </Compile> + <Compile Include="..\..\Numerics\BigIntegerBuilder.cs"> + <Link>Numerics\BigIntegerBuilder.cs</Link> + </Compile> + <Compile Include="..\..\Numerics\NumericHelpers.cs"> + <Link>Numerics\NumericHelpers.cs</Link> + </Compile> + <Compile Include="..\..\StringManager.cs"> + <Link>StringManager.cs</Link> + </Compile> + <Compile Include="..\..\Win32.cs"> + <Link>Win32.cs</Link> + </Compile> + <Compile Include="LicensingManagerTests.cs" /> + <Compile Include="UnitTest1.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <ItemGroup> + <WCFMetadata Include="Service References\" /> + </ItemGroup> + <Choose> + <When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'"> + <ItemGroup> + <Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <Private>False</Private> + </Reference> + <Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <Private>False</Private> + </Reference> + <Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <Private>False</Private> + </Reference> + <Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <Private>False</Private> + </Reference> + </ItemGroup> + </When> + </Choose> + <Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" /> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/runtime/VMProtect.Runtime/VMProtect.Netcore.csproj b/runtime/VMProtect.Runtime/VMProtect.Netcore.csproj new file mode 100644 index 0000000..ac6da52 --- /dev/null +++ b/runtime/VMProtect.Runtime/VMProtect.Netcore.csproj @@ -0,0 +1,65 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <OutputType>Library</OutputType> + <TargetFrameworks>netstandard2.1;netcoreapp3.0;net20;net40</TargetFrameworks> + <Platforms>AnyCPU;x64</Platforms> + </PropertyGroup> + + <ItemGroup Condition="'$(TargetFramework)' == 'net20' Or '$(TargetFramework)' == 'net40'"> + <Reference Include="System" /> + <Reference Include="System.Data" /> + <Reference Include="System.Security" /> + <Reference Include="System.Windows.Forms" /> + <Reference Include="System.Xml" /> + </ItemGroup> + + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> + <Optimize>true</Optimize> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <DefineConstants>$(DefineConstants);TRACE;RUNTIME</DefineConstants> + <OutputPath>..\..\bin\32\Release\</OutputPath> + </PropertyGroup> + + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Optimize>true</Optimize> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <DefineConstants>$(DefineConstants);TRACE;RUNTIME</DefineConstants> + <OutputPath>..\..\bin\64\Release\</OutputPath> + </PropertyGroup> + + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> + <Optimize>true</Optimize> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <DefineConstants>$(DefineConstants);TRACE;DEBUG;RUNTIME</DefineConstants> + <OutputPath>..\..\bin\32\Debug\</OutputPath> + </PropertyGroup> + + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Optimize>true</Optimize> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <DefineConstants>$(DefineConstants);TRACE;DEBUG;RUNTIME</DefineConstants> + <OutputPath>..\..\bin\64\Debug\</OutputPath> + </PropertyGroup> + + <ItemGroup> + <Compile Remove="Tests\**" /> + <Compile Remove="VMProtect.Netcore\**" /> + <Compile Remove="VMProtect.Runtime.Netstandard\**" /> + <EmbeddedResource Remove="Tests\**" /> + <EmbeddedResource Remove="VMProtect.Netcore\**" /> + <EmbeddedResource Remove="VMProtect.Runtime.Netstandard\**" /> + <None Remove="Tests\**" /> + <None Remove="VMProtect.Netcore\**" /> + <None Remove="VMProtect.Runtime.Netstandard\**" /> + </ItemGroup> + + <ItemGroup> + <Compile Remove="Properties\AssemblyInfo.cs" /> + </ItemGroup> + + <ItemGroup> + <Folder Include="Properties\" /> + </ItemGroup> + +</Project> diff --git a/runtime/VMProtect.Runtime/VMProtect.Runtime.csproj b/runtime/VMProtect.Runtime/VMProtect.Runtime.csproj new file mode 100644 index 0000000..84d6bec --- /dev/null +++ b/runtime/VMProtect.Runtime/VMProtect.Runtime.csproj @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{946D07D4-1AE4-4FC3-9A8C-563B5F64B0B6}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>VMProtect.Runtime</RootNamespace> + <AssemblyName>VMProtect.Runtime</AssemblyName> + <TargetFrameworkVersion>v4.8</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <TargetFrameworkProfile /> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>..\..\bin\32\Debug\</OutputPath> + <DefineConstants>TRACE;DEBUG;RUNTIME;NETFRAMEWORK</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <PlatformTarget>AnyCPU</PlatformTarget> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <Prefer32Bit>false</Prefer32Bit> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>..\..\bin\32\Release\</OutputPath> + <DefineConstants>TRACE;RUNTIME;NETFRAMEWORK</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <Prefer32Bit>false</Prefer32Bit> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"> + <DebugSymbols>true</DebugSymbols> + <OutputPath>..\..\bin\64\Debug\</OutputPath> + <DefineConstants>TRACE;DEBUG;RUNTIME;NETFRAMEWORK</DefineConstants> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <DebugType>full</DebugType> + <PlatformTarget>x64</PlatformTarget> + <ErrorReport>prompt</ErrorReport> + <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> + <Prefer32Bit>false</Prefer32Bit> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"> + <OutputPath>..\..\bin\64\Release\</OutputPath> + <DefineConstants>TRACE;RUNTIME;NETFRAMEWORK</DefineConstants> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <Optimize>true</Optimize> + <DebugType>pdbonly</DebugType> + <PlatformTarget>x64</PlatformTarget> + <ErrorReport>prompt</ErrorReport> + <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> + <Prefer32Bit>false</Prefer32Bit> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="System.Data" /> + <Reference Include="System.Security" /> + <Reference Include="System.Windows.Forms" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="LzmaDecoder.cs" /> + <Compile Include="Numerics\BigInteger.cs" /> + <Compile Include="Numerics\BigIntegerBuilder.cs" /> + <Compile Include="Crypto.cs" /> + <Compile Include="Core.cs" /> + <Compile Include="CpuId.cs" /> + <Compile Include="Faces.cs" /> + <Compile Include="HardwareID.cs" /> + <Compile Include="LicensingManager.cs" /> + <Compile Include="Loader.cs" /> + <Compile Include="Numerics\NumericHelpers.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="StringManager.cs" /> + <Compile Include="VirtualMachine.cs" /> + <Compile Include="Win32.cs" /> + </ItemGroup> + <ItemGroup /> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/runtime/VMProtect.Runtime/VirtualMachine.cs b/runtime/VMProtect.Runtime/VirtualMachine.cs new file mode 100644 index 0000000..dcc28d0 --- /dev/null +++ b/runtime/VMProtect.Runtime/VirtualMachine.cs @@ -0,0 +1,4285 @@ +using System; +using System.Reflection; +using System.Reflection.Emit; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; + +namespace VMProtect +{ + [VMProtect.DeleteOnCompilation] + internal enum OpCodes + { + icUnknown, icByte, icWord, icDword, icQword, icComment, icData, icCase, + icNop, icBreak, icLdarg_0, icLdarg_1, icLdarg_2, icLdarg_3, icLdloc_0, icLdloc_1, icLdloc_2, icLdloc_3, icStloc_0, icStloc_1, + icStloc_2, icStloc_3, icLdarg_s, icLdarga_s, icStarg_s, icLdloc_s, icLdloca_s, icStloc_s, icLdnull, icLdc_i4_m1, icLdc_i4_0, + icLdc_i4_1, icLdc_i4_2, icLdc_i4_3, icLdc_i4_4, icLdc_i4_5, icLdc_i4_6, icLdc_i4_7, icLdc_i4_8, icLdc_i4_s, icLdc_i4, icLdc_i8, + icLdc_r4, icLdc_r8, icDup, icPop, icJmp, icCall, icCalli, icRet, icBr_s, icBrfalse_s, icBrtrue_s, icBeq_s, icBge_s, icBgt_s, icBle_s, + icBlt_s, icBne_un_s, icBge_un_s, icBgt_un_s, icBle_un_s, icBlt_un_s, icBr, icBrfalse, icBrtrue, icBeq, icBge, icBgt, icBle, icBlt, + icBne_un, icBge_un, icBgt_un, icBle_un, icBlt_un, icSwitch, icLdind_i1, icLdind_u1, icLdind_i2, icLdind_u2, icLdind_i4, icLdind_u4, + icLdind_i8, icLdind_i, icLdind_r4, icLdind_r8, icLdind_ref, icStind_ref, icStind_i1, icStind_i2, icStind_i4, icStind_i8, icStind_r4, + icStind_r8, icAdd, icSub, icMul, icDiv, icDiv_un, icRem, icRem_un, icAnd, icOr, icXor, icShl, icShr, icShr_un, icNeg, icNot, icConv_i1, icConv_i2, + icConv_i4, icConv_i8, icConv_r4, icConv_r8, icConv_u4, icConv_u8, icCallvirt, icCpobj, icLdobj, icLdstr, icNewobj, icCastclass, + icIsinst, icConv_r_un, icUnbox, icThrow, icLdfld, icLdflda, icStfld, icLdsfld, icLdsflda, icStsfld, icStobj, icConv_ovf_i1_un, + icConv_ovf_i2_un, icConv_ovf_i4_un, icConv_ovf_i8_un, icConv_ovf_u1_un, icConv_ovf_u2_un, icConv_ovf_u4_un, icConv_ovf_u8_un, + icConv_ovf_i_un, icConv_ovf_u_un, icBox, icNewarr, icLdlen, icLdelema, icLdelem_i1, icLdelem_u1, icLdelem_i2, icLdelem_u2, + icLdelem_i4, icLdelem_u4, icLdelem_i8, icLdelem_i, icLdelem_r4, icLdelem_r8, icLdelem_ref, icStelem_i, icStelem_i1, icStelem_i2, + icStelem_i4, icStelem_i8, icStelem_r4, icStelem_r8, icStelem_ref, icLdelem, icStelem, icUnbox_any, icConv_ovf_i1, icConv_ovf_u1, + icConv_ovf_i2, icConv_ovf_u2, icConv_ovf_i4, icConv_ovf_u4, icConv_ovf_i8, icConv_ovf_u8, icRefanyval, icCkfinite, icMkrefany, + icLdtoken, icConv_u2, icConv_u1, icConv_i, icConv_ovf_i, icConv_ovf_u, icAdd_ovf, icAdd_ovf_un, icMul_ovf, icMul_ovf_un, icSub_ovf, + icSub_ovf_un, icEndfinally, icLeave, icLeave_s, icStind_i, icConv_u, icArglist, icCeq, icCgt, icCgt_un, icClt, icClt_un, icLdftn, icLdvirtftn, + icLdarg, icLdarga, icStarg, icLdloc, icLdloca, icStloc, icLocalloc, icEndfilter, icUnaligned, icVolatile, icTail, icInitobj, icConstrained, + icCpblk, icInitblk, icNo, icRethrow, icSizeof, icRefanytype, icReadonly, + icConv, icConv_ovf, icConv_ovf_un, icLdmem_i4, icInitarg, icInitcatchblock, icEntertry, icCallvm, icCallvmvirt, + icCmp, icCmp_un + } + + public class VirtualMachine + { + static class Utils + { + public static int Random() + { + return new Random().Next(); + } + + public static int CalcCRC(uint offset, uint size) + { + long instance = Marshal.GetHINSTANCE(typeof(CRC32).Module).ToInt64(); + return (int)new CRC32().Hash(new IntPtr(instance + offset), size); + } + + unsafe public static object BoxPointer(void* ptr) + { + return Pointer.Box(ptr, typeof(void*)); + } + + unsafe public static void* UnboxPointer(object ptr) + { + return Pointer.Unbox(ptr); + } + } + + abstract class BaseVariant + { + public abstract BaseVariant Clone(); + public abstract object Value(); + public abstract void SetValue(object value); + public virtual void SetFieldValue(FieldInfo field, object value) + { + var obj = Value(); + field.SetValue(obj, value); + } + + public virtual bool IsReference() + { + return false; + } + + public virtual StackableVariant ToStack() + { + throw new InvalidOperationException(); + } + + public virtual BaseVariant ToUnsigned() + { + return this; + } + + public virtual Type Type() + { + throw new InvalidOperationException(); + } + + public virtual TypeCode CalcTypeCode() + { + throw new InvalidOperationException(); + } + + public virtual bool ToBoolean() + { + return System.Convert.ToBoolean(Value()); + } + public virtual sbyte ToSByte() + { + return System.Convert.ToSByte(Value()); + } + public virtual short ToInt16() + { + return System.Convert.ToInt16(Value()); + } + public virtual int ToInt32() + { + return System.Convert.ToInt32(Value()); + } + public virtual long ToInt64() + { + return System.Convert.ToInt64(Value()); + } + public virtual char ToChar() + { + return System.Convert.ToChar(Value()); + } + public virtual byte ToByte() + { + return System.Convert.ToByte(Value()); + } + public virtual ushort ToUInt16() + { + return System.Convert.ToUInt16(Value()); + } + public virtual uint ToUInt32() + { + return System.Convert.ToUInt32(Value()); + } + public virtual ulong ToUInt64() + { + return System.Convert.ToUInt64(Value()); + } + public virtual float ToSingle() + { + return System.Convert.ToSingle(Value()); + } + public virtual double ToDouble() + { + return System.Convert.ToDouble(Value()); + } + + public override string ToString() + { + var v = Value(); + return v != null ? System.Convert.ToString(v) : null; + } + + public virtual IntPtr ToIntPtr() + { + var value = Value(); + if (value?.GetType() == typeof(IntPtr)) + return (IntPtr)value; + + throw new InvalidOperationException(); + } + + public virtual UIntPtr ToUIntPtr() + { + var value = Value(); + if (value?.GetType() == typeof(UIntPtr)) + return (UIntPtr)value; + + throw new InvalidOperationException(); + } + + public virtual unsafe void* ToPointer() + { + throw new InvalidOperationException(); + } + + public virtual object Conv_ovf(Type type, bool un) + { + throw new InvalidOperationException(); + } + } + + abstract class StackableVariant : BaseVariant + { + public override StackableVariant ToStack() + { + return this; + } + + public override TypeCode CalcTypeCode() + { + return TypeCode.Empty; + } + } + + sealed class IntVariant : StackableVariant + { + private int _value; + public IntVariant(int value) + { + _value = value; + } + + public override Type Type() + { + return typeof(int); + } + + public override TypeCode CalcTypeCode() + { + return TypeCode.Int32; + } + + public override BaseVariant Clone() + { + return new IntVariant(_value); + } + + public override object Value() + { + return _value; + } + + public override void SetValue(object value) + { + _value = System.Convert.ToInt32(value); + } + + public override bool ToBoolean() + { + return _value != 0; + } + + public override sbyte ToSByte() + { + return (sbyte)_value; + } + + public override short ToInt16() + { + return (short)_value; + } + public override int ToInt32() + { + return _value; + } + + public override long ToInt64() + { + return (long)_value; + } + + public override char ToChar() + { + return (char)_value; + } + + public override byte ToByte() + { + return (byte)_value; + } + public override ushort ToUInt16() + { + return (ushort)_value; + } + + public override uint ToUInt32() + { + return (uint)_value; + } + + public override ulong ToUInt64() + { + return (uint)_value; + } + + public override float ToSingle() + { + return _value; + } + + public override double ToDouble() + { + return (double)_value; + } + + public override IntPtr ToIntPtr() + { + return new IntPtr(_value); + } + + public override UIntPtr ToUIntPtr() + { + return new UIntPtr((uint)_value); + } + + public override BaseVariant ToUnsigned() + { + return new UintVariant((uint)_value); + } + + public override object Conv_ovf(Type type, bool un) + { + if (type == typeof(IntPtr)) + { + if (IntPtr.Size == 4) + return new IntPtr(un ? checked((int)(uint)_value) : _value); + return new IntPtr(un ? (long)(uint)_value : _value); + } + if (type == typeof(UIntPtr)) + return new UIntPtr(un ? (uint)_value : checked((uint)_value)); + + switch (System.Type.GetTypeCode(type)) { + case TypeCode.SByte: + return un ? checked((sbyte)(uint)_value) : checked((sbyte)_value); + case TypeCode.Int16: + return un ? checked((short)(uint)_value) : checked((short)_value); + case TypeCode.Int32: + return un ? checked((int)(uint)_value) : _value; + case TypeCode.Int64: + return un ? (long)(uint)_value : _value; + case TypeCode.Byte: + return un ? checked((byte)(uint)_value) : checked((byte)_value); + case TypeCode.UInt16: + return un ? checked((ushort)(uint)_value) : checked((ushort)_value); + case TypeCode.UInt32: + return un ? (uint)_value : checked((uint)_value); + case TypeCode.UInt64: + return un ? (uint)_value : checked((uint)_value); + case TypeCode.Double: + return un ? (double)(uint)_value : (double)_value; + } + + throw new ArgumentException(); + } + } + + sealed class LongVariant : StackableVariant + { + private long _value; + public LongVariant(long value) + { + _value = value; + } + + public override Type Type() + { + return typeof(long); + } + + public override TypeCode CalcTypeCode() + { + return TypeCode.Int64; + } + + public override BaseVariant ToUnsigned() + { + return new UlongVariant((ulong)_value); + } + + public override BaseVariant Clone() + { + return new LongVariant(_value); + } + + public override object Value() + { + return _value; + } + + public override void SetValue(object value) + { + _value = System.Convert.ToInt64(value); + } + + public override bool ToBoolean() + { + return _value != 0; + } + + public override char ToChar() + { + return (char)_value; + } + + public override byte ToByte() + { + return (byte)_value; + } + + public override sbyte ToSByte() + { + return (sbyte)_value; + } + + public override short ToInt16() + { + return (short)_value; + } + + public override int ToInt32() + { + return (int)_value; + } + + public override long ToInt64() + { + return _value; + } + + public override ushort ToUInt16() + { + return (ushort)_value; + } + + public override uint ToUInt32() + { + return (uint)_value; + } + + public override ulong ToUInt64() + { + return (ulong)_value; + } + + public override float ToSingle() + { + return _value; + } + + public override double ToDouble() + { + return (double)_value; + } + + public override IntPtr ToIntPtr() + { + return new IntPtr(IntPtr.Size == 4 ? (int)_value : _value); + } + + public override UIntPtr ToUIntPtr() + { + return new UIntPtr(UIntPtr.Size == 4 ? (uint)_value : (ulong)_value); + } + + public override object Conv_ovf(Type type, bool un) + { + if (type == typeof(IntPtr)) + return new IntPtr(un ? checked((long)(ulong)_value) : _value); + if (type == typeof(UIntPtr)) + return new UIntPtr(un ? (ulong)_value : checked((ulong)_value)); + + switch (System.Type.GetTypeCode(type)) + { + case TypeCode.SByte: + return un ? checked((sbyte)(ulong)_value) : checked((sbyte)_value); + case TypeCode.Int16: + return un ? checked((short)(ulong)_value) : checked((short)_value); + case TypeCode.Int32: + return un ? checked((int)(ulong)_value) : checked((int)_value); + case TypeCode.Int64: + return un ? checked((long)(ulong)_value) : _value; + case TypeCode.Byte: + return un ? checked((byte)(ulong)_value) : checked((byte)_value); + case TypeCode.UInt16: + return un ? checked((ushort)(uint)_value) : checked((ushort)_value); + case TypeCode.UInt32: + return un ? checked((uint)(ulong)_value) : checked((uint)_value); + case TypeCode.UInt64: + return un ? (ulong)_value : checked((ulong)_value); + case TypeCode.Double: + return un ? (double)(ulong)_value : (double)_value; + } + + throw new ArgumentException(); + } + } + + sealed class SingleVariant : StackableVariant + { + private float _value; + + public SingleVariant(float value) + { + _value = value; + } + + public override Type Type() + { + return typeof(float); + } + + public override TypeCode CalcTypeCode() + { + return TypeCode.Single; + } + + public override BaseVariant Clone() + { + return new SingleVariant(_value); + } + + public override object Value() + { + return _value; + } + + public override void SetValue(object value) + { + _value = System.Convert.ToSingle(value); + } + + public override bool ToBoolean() + { + return System.Convert.ToBoolean(_value); + } + + public override sbyte ToSByte() + { + return (sbyte)_value; + } + + public override short ToInt16() + { + return (short)_value; + } + + public override int ToInt32() + { + return (int)_value; + } + + public override long ToInt64() + { + return (long)_value; + } + + public override char ToChar() + { + return (char)_value; + } + + public override byte ToByte() + { + return (byte)_value; + } + + public override ushort ToUInt16() + { + return (ushort)_value; + } + + public override uint ToUInt32() + { + return (uint)_value; + } + + public override ulong ToUInt64() + { + return (ulong)_value; + } + + public override float ToSingle() + { + return _value; + } + + public override double ToDouble() + { + return _value; + } + + public override IntPtr ToIntPtr() + { + return new IntPtr(IntPtr.Size == 4 ? (int)_value : (long)_value); + } + + public override UIntPtr ToUIntPtr() + { + return new UIntPtr(IntPtr.Size == 4 ? (uint)_value : (ulong)_value); + } + + public override object Conv_ovf(Type type, bool un) + { + if (type == typeof(IntPtr)) + return new IntPtr(checked((long)_value)); + if (type == typeof(UIntPtr)) + return new UIntPtr(checked((ulong)_value)); + + switch (System.Type.GetTypeCode(type)) + { + case TypeCode.SByte: + return un ? checked((sbyte)(uint)_value) : checked((sbyte)_value); + case TypeCode.Int16: + return un ? checked((short)(uint)_value) : checked((short)_value); + case TypeCode.Int32: + return checked((int)_value); + case TypeCode.Byte: + return checked((byte)_value); + case TypeCode.UInt16: + return checked((ushort)_value); + case TypeCode.UInt32: + return checked((uint)_value); + case TypeCode.UInt64: + return checked((ulong)_value); + } + + throw new ArgumentException(); + } + } + + sealed class DoubleVariant : StackableVariant + { + private double _value; + + public DoubleVariant(double value) + { + _value = value; + } + + public override Type Type() + { + return typeof(double); + } + + public override TypeCode CalcTypeCode() + { + return TypeCode.Double; + } + + public override BaseVariant Clone() + { + return new DoubleVariant(_value); + } + + public override object Value() + { + return _value; + } + + public override void SetValue(object value) + { + _value = (double)value; + } + + public override bool ToBoolean() + { + return System.Convert.ToBoolean(_value); + } + + public override sbyte ToSByte() + { + return (sbyte)_value; + } + + public override short ToInt16() + { + return (short)_value; + } + + public override int ToInt32() + { + return (int)_value; + } + + public override long ToInt64() + { + return (long)_value; + } + + public override char ToChar() + { + return (char)_value; + } + + public override byte ToByte() + { + return (byte)_value; + } + + public override ushort ToUInt16() + { + return (ushort)_value; + } + + public override uint ToUInt32() + { + return (uint)_value; + } + + public override ulong ToUInt64() + { + return (ulong)_value; + } + + public override float ToSingle() + { + return (float)_value; + } + + public override double ToDouble() + { + return _value; + } + + public override IntPtr ToIntPtr() + { + return new IntPtr(IntPtr.Size == 4 ? (int)_value : (long)_value); + } + + public override UIntPtr ToUIntPtr() + { + return new UIntPtr(IntPtr.Size == 4 ? (uint)_value : (ulong)_value); + } + + public override object Conv_ovf(Type type, bool un) + { + if (type == typeof(IntPtr)) + return new IntPtr(checked((long)_value)); + if (type == typeof(UIntPtr)) + return new UIntPtr(checked((ulong)_value)); + + switch (System.Type.GetTypeCode(type)) + { + case TypeCode.SByte: + return un ? checked((sbyte)(uint)_value) : checked((sbyte)_value); + case TypeCode.Int16: + return un ? checked((short)(uint)_value) : checked((short)_value); + case TypeCode.Int32: + return checked((int)_value); + case TypeCode.Int64: + return checked((long)_value); + case TypeCode.Byte: + return checked((byte)_value); + case TypeCode.UInt16: + return checked((ushort)_value); + case TypeCode.UInt32: + return checked((uint)_value); + case TypeCode.UInt64: + return checked((ulong)_value); + case TypeCode.Double: + return _value; + } + + throw new ArgumentException(); + } + } + + sealed class StringVariant : StackableVariant + { + private string _value; + + public StringVariant(string value) + { + _value = value; + } + + public override Type Type() + { + return typeof(string); + } + + public override TypeCode CalcTypeCode() + { + return TypeCode.Object; + } + + public override BaseVariant Clone() + { + return new StringVariant(_value); + } + + public override object Value() + { + return _value; + } + + public override void SetValue(object value) + { + _value = (value != null) ? System.Convert.ToString(value) : null; + } + + public override bool ToBoolean() + { + return _value != null; + } + + public override string ToString() + { + return _value; + } + } + + sealed class ShortVariant : BaseVariant + { + private short _value; + + public ShortVariant(short value) + { + _value = value; + } + + public override Type Type() + { + return typeof(short); + } + + public override BaseVariant Clone() + { + return new ShortVariant(_value); + } + + public override object Value() + { + return _value; + } + + public override void SetValue(object value) + { + _value = System.Convert.ToInt16(value); + } + + public override StackableVariant ToStack() + { + return new IntVariant(ToInt32()); + } + + public override sbyte ToSByte() + { + return (sbyte)_value; + } + + public override byte ToByte() + { + return (byte)_value; + } + + public override short ToInt16() + { + return _value; + } + + public override ushort ToUInt16() + { + return (ushort)_value; + } + + public override int ToInt32() + { + return _value; + } + + public override uint ToUInt32() + { + return (uint)_value; + } + } + + sealed class UshortVariant : BaseVariant + { + private ushort _value; + + public UshortVariant(ushort value) + { + _value = value; + } + + public override Type Type() + { + return typeof(ushort); + } + + public override BaseVariant Clone() + { + return new UshortVariant(_value); + } + + public override object Value() + { + return _value; + } + + public override void SetValue(object value) + { + _value = System.Convert.ToUInt16(value); + } + + public override StackableVariant ToStack() + { + return new IntVariant(ToInt32()); + } + + public override sbyte ToSByte() + { + return (sbyte)_value; + } + + public override byte ToByte() + { + return (byte)_value; + } + + public override short ToInt16() + { + return (short)_value; + } + + public override ushort ToUInt16() + { + return _value; + } + + public override int ToInt32() + { + return _value; + } + + public override uint ToUInt32() + { + return _value; + } + } + + sealed class BoolVariant : BaseVariant + { + private bool _value; + + public BoolVariant(bool value) + { + _value = value; + } + + public override Type Type() + { + return typeof(bool); + } + + public override BaseVariant Clone() + { + return new BoolVariant(_value); + } + + public override object Value() + { + return _value; + } + + public override void SetValue(object value) + { + _value = System.Convert.ToBoolean(value); + } + + public override StackableVariant ToStack() + { + return new IntVariant(ToInt32()); + } + + public override int ToInt32() + { + return _value ? 1 : 0; + } + } + + sealed class CharVariant : BaseVariant + { + private char _value; + + public CharVariant(char value) + { + _value = value; + } + + public override Type Type() + { + return typeof(char); + } + + public override BaseVariant Clone() + { + return new CharVariant(_value); + } + + public override object Value() + { + return _value; + } + + public override void SetValue(object value) + { + _value = System.Convert.ToChar(value); + } + + public override StackableVariant ToStack() + { + return new IntVariant(ToInt32()); + } + + public override sbyte ToSByte() + { + return (sbyte)_value; + } + + public override byte ToByte() + { + return (byte)_value; + } + + public override short ToInt16() + { + return (short)_value; + } + + public override ushort ToUInt16() + { + return _value; + } + + public override int ToInt32() + { + return _value; + } + + public override uint ToUInt32() + { + return _value; + } + } + + sealed class ByteVariant : BaseVariant + { + private byte _value; + + public ByteVariant(byte value) + { + _value = value; + } + + public override Type Type() + { + return typeof(byte); + } + + public override BaseVariant Clone() + { + return new ByteVariant(_value); + } + + public override object Value() + { + return _value; + } + + public override void SetValue(object value) + { + _value = System.Convert.ToByte(value); + } + + public override StackableVariant ToStack() + { + return new IntVariant(ToInt32()); + } + + public override sbyte ToSByte() + { + return (sbyte)_value; + } + + public override byte ToByte() + { + return _value; + } + + public override short ToInt16() + { + return _value; + } + + public override ushort ToUInt16() + { + return _value; + } + + public override int ToInt32() + { + return _value; + } + public override uint ToUInt32() + { + return _value; + } + } + + sealed class SbyteVariant : BaseVariant + { + private sbyte _value; + + public SbyteVariant(sbyte value) + { + _value = value; + } + + public override Type Type() + { + return typeof(sbyte); + } + + public override BaseVariant Clone() + { + return new SbyteVariant(_value); + } + + public override object Value() + { + return _value; + } + + public override void SetValue(object value) + { + _value = System.Convert.ToSByte(value); + } + + public override StackableVariant ToStack() + { + return new IntVariant(ToInt32()); + } + + public override sbyte ToSByte() + { + return _value; + } + + public override byte ToByte() + { + return (byte)_value; + } + + public override short ToInt16() + { + return _value; + } + + public override ushort ToUInt16() + { + return (ushort)_value; + } + + public override int ToInt32() + { + return _value; + } + + public override uint ToUInt32() + { + return (uint)_value; + } + } + + sealed class UintVariant : BaseVariant + { + private uint _value; + public UintVariant(uint value) + { + _value = value; + } + + public override Type Type() + { + return typeof(uint); + } + + public override BaseVariant Clone() + { + return new UintVariant(_value); + } + + public override object Value() + { + return _value; + } + + public override void SetValue(object value) + { + _value = System.Convert.ToUInt32(value); + } + + public override StackableVariant ToStack() + { + return new IntVariant(ToInt32()); + } + + public override sbyte ToSByte() + { + return (sbyte)_value; + } + + public override byte ToByte() + { + return (byte)_value; + } + + public override short ToInt16() + { + return (short)_value; + } + + public override ushort ToUInt16() + { + return (ushort)_value; + } + + public override int ToInt32() + { + return (int)_value; + } + + public override uint ToUInt32() + { + return _value; + } + } + + sealed class UlongVariant : BaseVariant + { + private ulong _value; + public UlongVariant(ulong value) + { + _value = value; + } + + public override Type Type() + { + return typeof(ulong); + } + + public override BaseVariant Clone() + { + return new UlongVariant(_value); + } + + public override object Value() + { + return _value; + } + + public override void SetValue(object value) + { + _value = System.Convert.ToUInt64(value); + } + + public override StackableVariant ToStack() + { + return new LongVariant(ToInt64()); + } + + public override sbyte ToSByte() + { + return (sbyte)_value; + } + + public override byte ToByte() + { + return (byte)_value; + } + + public override short ToInt16() + { + return (short)_value; + } + + public override ushort ToUInt16() + { + return (ushort)_value; + } + + public override int ToInt32() + { + return (int)_value; + } + + public override uint ToUInt32() + { + return (uint)_value; + } + + public override long ToInt64() + { + return (long)_value; + } + + public override ulong ToUInt64() + { + return _value; + } + } + + sealed class ObjectVariant : StackableVariant + { + private object _value; + + public ObjectVariant(object value) + { + _value = value; + } + + public override Type Type() + { + return typeof(object); + } + + public override TypeCode CalcTypeCode() + { + return TypeCode.Object; + } + + public override BaseVariant Clone() + { + return new ObjectVariant(_value); + } + + public override object Value() + { + return _value; + } + + public override void SetValue(object value) + { + _value = value; + } + + public override bool ToBoolean() + { + return _value != null; + } + } + + sealed class PointerVariant : StackableVariant + { + private object _value; + private Type _type; + private BaseVariant _variant; + + public PointerVariant(object value, Type type) + { + _value = value; + _type = type; + _variant = ToVariant(value); + } + + private static BaseVariant ToVariant(object value) + { + unsafe + { + IntPtr ptr = value == null ? IntPtr.Zero : new IntPtr(Pointer.Unbox(value)); + if (IntPtr.Size == 4) + return new IntVariant(ptr.ToInt32()); + else + return new LongVariant(ptr.ToInt64()); + } + } + + public override Type Type() + { + return _type; + } + + public override TypeCode CalcTypeCode() + { + return (IntPtr.Size == 4) ? TypeCode.UInt32 : TypeCode.UInt64; + } + + public override BaseVariant Clone() + { + return new PointerVariant(_value, _type); + } + + public override object Value() + { + return _value; + } + + public override void SetValue(object value) + { + _value = value; + _variant = ToVariant(value); + } + + public override bool ToBoolean() + { + return _value != null; + } + + public override sbyte ToSByte() + { + return _variant.ToSByte(); + } + + public override short ToInt16() + { + return _variant.ToInt16(); + } + + public override int ToInt32() + { + return _variant.ToInt32(); + } + + public override long ToInt64() + { + return _variant.ToInt64(); + } + + public override byte ToByte() + { + return _variant.ToByte(); + } + + public override ushort ToUInt16() + { + return _variant.ToUInt16(); + } + + public override uint ToUInt32() + { + return _variant.ToUInt32(); + } + + public override ulong ToUInt64() + { + return _variant.ToUInt64(); + } + + public override float ToSingle() + { + return _variant.ToSingle(); + } + + public override double ToDouble() + { + return _variant.ToDouble(); + } + + public override IntPtr ToIntPtr() + { + return _variant.ToIntPtr(); + } + + public override UIntPtr ToUIntPtr() + { + return _variant.ToUIntPtr(); + } + + public override unsafe void* ToPointer() + { + return Pointer.Unbox(_value); + } + + public override object Conv_ovf(Type type, bool un) + { + return _variant.Conv_ovf(type, un); + } + } + + sealed class ValueTypeVariant : StackableVariant + { + private object _value; + + public ValueTypeVariant(object value) + { + if (value != null && !(value is ValueType)) + throw new ArgumentException(); + _value = value; + } + + public override Type Type() + { + return typeof(ValueType); + } + + public override BaseVariant Clone() + { + object value; + if (_value == null) + { + value = null; + } + else + { + var type = _value.GetType(); + var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + value = Activator.CreateInstance(type); + foreach (var field in fields) + { + field.SetValue(value, field.GetValue(_value)); + } + } + + return new ValueTypeVariant(value); + } + + public override object Value() + { + return _value; + } + + public override void SetValue(object value) + { + if (value != null && !(value is ValueType)) + throw new ArgumentException(); + _value = value; + } + } + + sealed class ArrayVariant : StackableVariant + { + private Array _value; + + public ArrayVariant(Array value) + { + _value = value; + } + + public override Type Type() + { + return typeof(Array); + } + + public override BaseVariant Clone() + { + return new ArrayVariant(_value); + } + + public override object Value() + { + return _value; + } + + public override void SetValue(object value) + { + _value = (Array)value; + } + + public override bool ToBoolean() + { + return _value != null; + } + } + + abstract class BaseReferenceVariant : StackableVariant + { + public override bool IsReference() + { + return true; + } + } + + sealed class ReferenceVariant : BaseReferenceVariant + { + private BaseVariant _variable; + + public ReferenceVariant(BaseVariant variable) + { + _variable = variable; + } + + public override Type Type() + { + return _variable.Type(); + } + + public override BaseVariant Clone() + { + return new ReferenceVariant(_variable); + } + + public override object Value() + { + return _variable.Value(); + } + + public override void SetValue(object value) + { + _variable.SetValue(value); + } + + public override bool ToBoolean() + { + return _variable != null; + } + + public override void SetFieldValue(FieldInfo field, object value) + { + _variable.SetFieldValue(field, value); + } + } + + sealed class NullReferenceVariant : BaseReferenceVariant + { + private Type _type; + + public NullReferenceVariant(Type type) + { + _type = type; + } + + public override Type Type() + { + return _type; + } + + public override BaseVariant Clone() + { + return new NullReferenceVariant(_type); + } + + public override object Value() + { + throw new InvalidOperationException(); + } + + public override void SetValue(object value) + { + throw new InvalidOperationException(); + } + + public override void SetFieldValue(FieldInfo field, object value) + { + throw new InvalidOperationException(); + } + } + + sealed class ArgReferenceVariant : BaseReferenceVariant + { + private BaseVariant _variable; + private BaseVariant _arg; + + public ArgReferenceVariant(BaseVariant variable, BaseVariant arg) + { + _variable = variable; + _arg = arg; + } + + public override Type Type() + { + return _variable.Type(); + } + + public override BaseVariant Clone() + { + return new ArgReferenceVariant(_variable, _arg); + } + + public override object Value() + { + return _variable.Value(); + } + + public override void SetValue(object value) + { + _variable.SetValue(value); + _arg.SetValue(_variable.Value()); + } + + public override bool ToBoolean() + { + return _variable != null; + } + } + + sealed class FieldReferenceVariant : BaseReferenceVariant + { + private FieldInfo _field; + private BaseVariant _variable; + + public FieldReferenceVariant(FieldInfo field, BaseVariant variable) + { + _field = field; + _variable = variable; + } + + public override Type Type() + { + return _field.FieldType; + } + + public override BaseVariant Clone() + { + return new FieldReferenceVariant(_field, _variable); + } + + public override object Value() + { + return _field.GetValue(_variable.Value()); + } + + public override void SetValue(object value) + { + _variable.SetFieldValue(_field, value); + } + } + + sealed class ArrayElementVariant : BaseReferenceVariant + { + private Array _value; + private int _index; + + public ArrayElementVariant(Array value, int index) + { + _value = value; + _index = index; + } + + public override Type Type() + { + return _value.GetType().GetElementType(); + } + + public override BaseVariant Clone() + { + return new ArrayElementVariant(_value, _index); + } + + public override object Value() + { + return _value.GetValue(_index); + } + + public override void SetValue(object value) + { + switch (System.Type.GetTypeCode(_value.GetType().GetElementType())) + { + case TypeCode.SByte: + value = System.Convert.ToSByte(value); + break; + case TypeCode.Byte: + value = System.Convert.ToByte(value); + break; + case TypeCode.Char: + value = System.Convert.ToChar(value); + break; + case TypeCode.Int16: + value = System.Convert.ToInt16(value); + break; + case TypeCode.UInt16: + value = System.Convert.ToUInt16(value); + break; + case TypeCode.Int32: + value = System.Convert.ToInt32(value); + break; + case TypeCode.UInt32: + value = System.Convert.ToUInt32(value); + break; + case TypeCode.Int64: + value = System.Convert.ToInt64(value); + break; + case TypeCode.UInt64: + value = System.Convert.ToUInt64(value); + break; + } + + _value.SetValue(value, _index); + } + + public override void SetFieldValue(FieldInfo field, object value) + { + var obj = Value(); + field.SetValue(obj, value); + if (obj is ValueType) + SetValue(obj); + } + + public override UIntPtr ToUIntPtr() + { + var dynamicMethod = new DynamicMethod("", typeof(UIntPtr), new Type[] { _value.GetType(), typeof(int) }, typeof(VirtualMachine).Module, true); + var gen = dynamicMethod.GetILGenerator(); + gen.Emit(System.Reflection.Emit.OpCodes.Ldarg, 0); + gen.Emit(System.Reflection.Emit.OpCodes.Ldarg, 1); + gen.Emit(System.Reflection.Emit.OpCodes.Ldelema, _value.GetType().GetElementType()); + gen.Emit(System.Reflection.Emit.OpCodes.Conv_U); + gen.Emit(System.Reflection.Emit.OpCodes.Ret); + + return (UIntPtr)dynamicMethod.Invoke(null, new object[] { _value, _index }); + } + } + + sealed class MethodVariant : StackableVariant + { + private MethodBase _value; + + public MethodVariant(MethodBase value) + { + _value = value; + } + + public override Type Type() + { + return typeof(MethodBase); + } + + public override BaseVariant Clone() + { + return new MethodVariant(_value); + } + + public override object Value() + { + return _value; + } + + public override void SetValue(object value) + { + _value = (MethodBase)value; + } + + public override bool ToBoolean() + { + return _value != null; + } + + public override IntPtr ToIntPtr() + { + return _value.MethodHandle.GetFunctionPointer(); + } + } + + sealed class IntPtrVariant : StackableVariant + { + IntPtr _value; + private BaseVariant _variant; + + public IntPtrVariant(IntPtr value) + { + _value = value; + _variant = ToVariant(_value); + } + + private static BaseVariant ToVariant(IntPtr value) + { + if (IntPtr.Size == 4) + return new IntVariant(value.ToInt32()); + else + return new LongVariant(value.ToInt64()); + } + + public override Type Type() + { + return typeof(IntPtr); + } + + public override TypeCode CalcTypeCode() + { + return _variant.CalcTypeCode(); + } + + public override BaseVariant Clone() + { + return new IntPtrVariant(_value); + } + + public override object Value() + { + return _value; + } + + public override void SetValue(object value) + { + _value = (IntPtr)value; + _variant = ToVariant(_value); + } + + public override bool ToBoolean() + { + return _value != IntPtr.Zero; + } + + public override sbyte ToSByte() + { + return _variant.ToSByte(); + } + + public override short ToInt16() + { + return _variant.ToInt16(); + } + + public override int ToInt32() + { + return _variant.ToInt32(); + } + + public override long ToInt64() + { + return _variant.ToInt64(); + } + + public override byte ToByte() + { + return _variant.ToByte(); + } + + public override ushort ToUInt16() + { + return _variant.ToUInt16(); + } + + public override uint ToUInt32() + { + return _variant.ToUInt32(); + } + + public override ulong ToUInt64() + { + return _variant.ToUInt64(); + } + + public override float ToSingle() + { + return _variant.ToSingle(); + } + + public override double ToDouble() + { + return _variant.ToDouble(); + } + + public override IntPtr ToIntPtr() + { + return _value; + } + + public override UIntPtr ToUIntPtr() + { + return _variant.ToUIntPtr(); + } + + public override unsafe void* ToPointer() + { + return _value.ToPointer(); + } + + public override object Conv_ovf(Type type, bool un) + { + return _variant.Conv_ovf(type, un); + } + } + + sealed class UIntPtrVariant : StackableVariant + { + private UIntPtr _value; + private BaseVariant _variant; + + public UIntPtrVariant(UIntPtr value) + { + _value = value; + _variant = ToVariant(_value); + } + + private static BaseVariant ToVariant(UIntPtr value) + { + if (IntPtr.Size == 4) + return new IntVariant((int)value.ToUInt32()); + else + return new LongVariant((long)value.ToUInt64()); + } + + public override Type Type() + { + return typeof(UIntPtr); + } + + public override TypeCode CalcTypeCode() + { + return _variant.CalcTypeCode(); + } + + public override BaseVariant Clone() + { + return new UIntPtrVariant(_value); + } + + public override object Value() + { + return _value; + } + + public override void SetValue(object value) + { + _value = (UIntPtr)value; + _variant = ToVariant(_value); + } + + public override bool ToBoolean() + { + return _value != UIntPtr.Zero; + } + + public override sbyte ToSByte() + { + return _variant.ToSByte(); + } + + public override short ToInt16() + { + return _variant.ToInt16(); + } + + public override int ToInt32() + { + return _variant.ToInt32(); + } + + public override long ToInt64() + { + return _variant.ToInt64(); + } + + public override byte ToByte() + { + return _variant.ToByte(); + } + + public override ushort ToUInt16() + { + return _variant.ToUInt16(); + } + + public override uint ToUInt32() + { + return _variant.ToUInt32(); + } + + public override ulong ToUInt64() + { + return _variant.ToUInt64(); + } + + public override float ToSingle() + { + return _variant.ToSingle(); + } + + public override double ToDouble() + { + return _variant.ToDouble(); + } + + public override IntPtr ToIntPtr() + { + return _variant.ToIntPtr(); + } + + public override UIntPtr ToUIntPtr() + { + return _value; + } + + public override unsafe void* ToPointer() + { + return _value.ToPointer(); + } + + public override object Conv_ovf(Type type, bool un) + { + return _variant.Conv_ovf(type, un); + } + } + + sealed class EnumVariant : StackableVariant + { + private Enum _value; + private BaseVariant _variant; + + public EnumVariant(Enum value) + { + if (value == null) + throw new ArgumentException(); + _value = value; + _variant = ToVariant(_value); + } + + private static BaseVariant ToVariant(Enum value) + { + switch (value.GetTypeCode()) + { + case TypeCode.Byte: + case TypeCode.UInt16: + case TypeCode.UInt32: + return new IntVariant((int)System.Convert.ToUInt32(value)); + case TypeCode.SByte: + case TypeCode.Int16: + case TypeCode.Int32: + return new IntVariant(System.Convert.ToInt32(value)); + case TypeCode.UInt64: + return new LongVariant((long)System.Convert.ToUInt64(value)); + case TypeCode.Int64: + return new LongVariant(System.Convert.ToInt64(value)); + default: + throw new InvalidOperationException(); + } + } + + public override BaseVariant ToUnsigned() + { + return _variant.ToUnsigned(); + } + + public override Type Type() + { + return _value.GetType(); + } + + public override TypeCode CalcTypeCode() + { + return _variant.CalcTypeCode(); + } + + public override BaseVariant Clone() + { + return new EnumVariant(_value); + } + + public override object Value() + { + return _value; + } + + public override void SetValue(object value) + { + if (value == null) + throw new ArgumentException(); + _value = (Enum)value; + _variant = ToVariant(_value); + } + + public override byte ToByte() + { + return _variant.ToByte(); + } + + public override sbyte ToSByte() + { + return _variant.ToSByte(); + } + + public override short ToInt16() + { + return _variant.ToInt16(); + } + + public override ushort ToUInt16() + { + return _variant.ToUInt16(); + } + + public override int ToInt32() + { + return _variant.ToInt32(); + } + + public override uint ToUInt32() + { + return _variant.ToUInt32(); + } + + public override long ToInt64() + { + return _variant.ToInt64(); + } + + public override ulong ToUInt64() + { + return _variant.ToUInt64(); + } + + public override float ToSingle() + { + return _variant.ToSingle(); + } + public override double ToDouble() + { + return _variant.ToDouble(); + } + + public override IntPtr ToIntPtr() + { + return new IntPtr(IntPtr.Size == 4 ? ToInt32() : ToInt64()); + } + + public override UIntPtr ToUIntPtr() + { + return new UIntPtr(IntPtr.Size == 4 ? ToUInt32() : ToUInt64()); + } + + public override object Conv_ovf(Type type, bool un) + { + return _variant.Conv_ovf(type, un); + } + } + + sealed class PointerReference : BaseReferenceVariant + { + private IntPtr _value; + private Type _type; + public PointerReference(IntPtr value, Type type) + { + _value = value; + _type = type; + } + + public override Type Type() + { + return typeof(Pointer); + } + + public override TypeCode CalcTypeCode() + { + return TypeCode.Empty; + } + + public override BaseVariant Clone() + { + return new PointerReference(_value, _type); + } + + public override object Value() + { + if (_type.IsValueType) + return Marshal.PtrToStructure(_value, _type); + + throw new InvalidOperationException(); + } + + public override void SetValue(object value) + { + if (value == null) + throw new ArgumentException(); + + if (_type.IsValueType) + { + Marshal.StructureToPtr(value, _value, false); + return; + } + + switch (System.Type.GetTypeCode(value.GetType())) + { + case TypeCode.SByte: + Marshal.WriteByte(_value, (byte)System.Convert.ToSByte(value)); + break; + case TypeCode.Byte: + Marshal.WriteByte(_value, System.Convert.ToByte(value)); + break; + case TypeCode.Char: + Marshal.WriteInt16(_value, System.Convert.ToChar(value)); + break; + case TypeCode.Int16: + Marshal.WriteInt16(_value, System.Convert.ToInt16(value)); + break; + case TypeCode.UInt16: + Marshal.WriteInt16(_value, (short)System.Convert.ToUInt16(value)); + break; + case TypeCode.Int32: + Marshal.WriteInt32(_value, System.Convert.ToInt32(value)); + break; + case TypeCode.UInt32: + Marshal.WriteInt32(_value, (int)System.Convert.ToUInt32(value)); + break; + case TypeCode.Int64: + Marshal.WriteInt64(_value, System.Convert.ToInt64(value)); + break; + case TypeCode.UInt64: + Marshal.WriteInt64(_value, (long)System.Convert.ToUInt64(value)); + break; + case TypeCode.Single: + Marshal.WriteInt32(_value, BitConverter.ToInt32(BitConverter.GetBytes(System.Convert.ToSingle(value)), 0)); + break; + case TypeCode.Double: + Marshal.WriteInt64(_value, BitConverter.ToInt64(BitConverter.GetBytes(System.Convert.ToDouble(value)), 0)); + break; + default: + throw new ArgumentException(); + } + } + + public override sbyte ToSByte() + { + return (sbyte)Marshal.ReadByte(_value); + } + + public override short ToInt16() + { + return Marshal.ReadInt16(_value); + } + + public override int ToInt32() + { + return Marshal.ReadInt32(_value); + } + + public override long ToInt64() + { + return Marshal.ReadInt64(_value); + } + + public override char ToChar() + { + return (char)Marshal.ReadInt16(_value); + } + + public override byte ToByte() + { + return Marshal.ReadByte(_value); + } + public override ushort ToUInt16() + { + return (ushort)Marshal.ReadInt16(_value); + } + + public override uint ToUInt32() + { + return (uint)Marshal.ReadInt32(_value); + } + + public override ulong ToUInt64() + { + return (ulong)Marshal.ReadInt64(_value); + } + + public override float ToSingle() + { + return BitConverter.ToSingle(BitConverter.GetBytes(Marshal.ReadInt32(_value)), 0); + } + + public override double ToDouble() + { + return BitConverter.ToDouble(BitConverter.GetBytes(Marshal.ReadInt64(_value)), 0); + } + + public override IntPtr ToIntPtr() + { + return new IntPtr(IntPtr.Size == 4 ? Marshal.ReadInt32(_value) : Marshal.ReadInt64(_value)); + } + + public override UIntPtr ToUIntPtr() + { + return new UIntPtr(IntPtr.Size == 4 ? (uint)Marshal.ReadInt32(_value) : (ulong)Marshal.ReadInt64(_value)); + } + } + + private sealed class CatchBlock + { + private byte _type; + private int _handler; + private int _filter; + public CatchBlock(byte type, int handler, int filter) + { + _type = type; + _handler = handler; + _filter = filter; + } + + public byte Type() + { + return _type; + } + public int Handler() + { + return _handler; + } + + public int Filter() + { + return _filter; + } + } + + private sealed class TryBlock + { + private int _begin; + private int _end; + private List<CatchBlock> _catchBlocks = new List<CatchBlock>(); + + public TryBlock(int begin, int end) + { + _begin = begin; + _end = end; + } + + public int Begin() + { + return _begin; + } + public int End() + { + return _end; + } + + public int CompareTo(TryBlock compare) + { + if (compare == null) + return 1; + + int res = _begin.CompareTo(compare.Begin()); + if (res == 0) + res = compare.End().CompareTo(_end); + return res; + } + + public void AddCatchBlock(byte type, int handler, int filter) + { + _catchBlocks.Add(new CatchBlock(type, handler, filter)); + } + + public List<CatchBlock> CatchBlocks() + { + return _catchBlocks; + } + } + + internal delegate void Handler(); + private readonly Dictionary<uint, Handler> _handlers = new Dictionary<uint, Handler>(); + + private readonly Module _module = typeof(VirtualMachine).Module; + private readonly long _instance; + private int _pos; + private Type _constrained; + private Stack<StackableVariant> _stack = new Stack<StackableVariant>(); + private static readonly Dictionary<int, object> _cache = new Dictionary<int, object>(); + private static readonly Dictionary<MethodBase, DynamicMethod> _dynamicMethodCache = new Dictionary<MethodBase, DynamicMethod>(); + private List<BaseVariant> _args = new List<BaseVariant>(); + private List<TryBlock> _tryBlocks = new List<TryBlock>(); + private Stack<TryBlock> _tryStack = new Stack<TryBlock>(); + private Stack<int> _finallyStack = new Stack<int>(); + private Exception _exception; + private CatchBlock _filterBlock; + private List<IntPtr> _localloc = new List<IntPtr>(); + + public VirtualMachine() + { + _instance = Marshal.GetHINSTANCE(_module).ToInt64(); + + _handlers[(uint)OpCodes.icInitarg] = Initarg; + _handlers[(uint)OpCodes.icInitcatchblock] = Initcatchblock; + _handlers[(uint)OpCodes.icEntertry] = Entertry; + _handlers[(uint)OpCodes.icLdc_i4] = Ldc_i4; + _handlers[(uint)OpCodes.icLdc_i8] = Ldc_i8; + _handlers[(uint)OpCodes.icLdc_r4] = Ldc_r4; + _handlers[(uint)OpCodes.icLdc_r8] = Ldc_r8; + _handlers[(uint)OpCodes.icLdnull] = Ldnull; + _handlers[(uint)OpCodes.icLdstr] = Ldstr; + _handlers[(uint)OpCodes.icDup] = Dup; + _handlers[(uint)OpCodes.icAdd] = Add_; + _handlers[(uint)OpCodes.icAdd_ovf] = Add_ovf; + _handlers[(uint)OpCodes.icAdd_ovf_un] = Add_ovf_un; + _handlers[(uint)OpCodes.icSub] = Sub_; + _handlers[(uint)OpCodes.icSub_ovf] = Sub_ovf; + _handlers[(uint)OpCodes.icSub_ovf_un] = Sub_ovf_un; + _handlers[(uint)OpCodes.icMul] = Mul_; + _handlers[(uint)OpCodes.icMul_ovf] = Mul_ovf; + _handlers[(uint)OpCodes.icMul_ovf_un] = Mul_ovf_un; + _handlers[(uint)OpCodes.icDiv] = Div_; + _handlers[(uint)OpCodes.icDiv_un] = Div_un; + _handlers[(uint)OpCodes.icRem] = Rem_; + _handlers[(uint)OpCodes.icRem_un] = Rem_un; + _handlers[(uint)OpCodes.icAnd] = And_; + _handlers[(uint)OpCodes.icOr] = Or_; + _handlers[(uint)OpCodes.icXor] = Xor_; + _handlers[(uint)OpCodes.icNot] = Not_; + _handlers[(uint)OpCodes.icNeg] = Neg_; + _handlers[(uint)OpCodes.icShr] = Shr_; + _handlers[(uint)OpCodes.icShr_un] = Shr_un; + _handlers[(uint)OpCodes.icShl] = Shl_; + _handlers[(uint)OpCodes.icConv] = Conv; + _handlers[(uint)OpCodes.icConv_ovf] = Conv_ovf; + _handlers[(uint)OpCodes.icConv_ovf_un] = Conv_ovf_un; + _handlers[(uint)OpCodes.icSizeof] = Sizeof; + _handlers[(uint)OpCodes.icLdind_ref] = Ldind; + _handlers[(uint)OpCodes.icLdfld] = Ldfld; + _handlers[(uint)OpCodes.icLdflda] = Ldflda; + _handlers[(uint)OpCodes.icStfld] = Stfld; + _handlers[(uint)OpCodes.icStsfld] = Stsfld; + _handlers[(uint)OpCodes.icStind_ref] = Stind; + _handlers[(uint)OpCodes.icLdarg] = Ldarg; + _handlers[(uint)OpCodes.icLdarga] = Ldarga; + _handlers[(uint)OpCodes.icStarg] = Starg; + _handlers[(uint)OpCodes.icConstrained] = Constrained; + _handlers[(uint)OpCodes.icCall] = Call_; + _handlers[(uint)OpCodes.icCallvirt] = Callvirt; + _handlers[(uint)OpCodes.icCalli] = Calli; + _handlers[(uint)OpCodes.icCallvm] = Callvm_; + _handlers[(uint)OpCodes.icCallvmvirt] = Callvmvirt; + _handlers[(uint)OpCodes.icNewobj] = Newobj_; + _handlers[(uint)OpCodes.icInitobj] = Initobj; + _handlers[(uint)OpCodes.icCmp] = Cmp; + _handlers[(uint)OpCodes.icCmp_un] = Cmp_un; + _handlers[(uint)OpCodes.icNewarr] = Newarr; + _handlers[(uint)OpCodes.icStelem_ref] = Stelem; + _handlers[(uint)OpCodes.icLdelem_ref] = Ldelem; + _handlers[(uint)OpCodes.icLdlen] = Ldlen; + _handlers[(uint)OpCodes.icLdelema] = Ldelema; + _handlers[(uint)OpCodes.icLdftn] = Ldftn; + _handlers[(uint)OpCodes.icLdvirtftn] = Ldvirtftn; + _handlers[(uint)OpCodes.icBr] = Br; + _handlers[(uint)OpCodes.icPop] = Pop_; + _handlers[(uint)OpCodes.icLeave] = Leave; + _handlers[(uint)OpCodes.icEndfinally] = Endfinally; + _handlers[(uint)OpCodes.icEndfilter] = Endfilter; + _handlers[(uint)OpCodes.icBox] = Box; + _handlers[(uint)OpCodes.icUnbox] = Unbox; + _handlers[(uint)OpCodes.icUnbox_any] = Unbox_any; + _handlers[(uint)OpCodes.icLdmem_i4] = Ldmem_i4; + _handlers[(uint)OpCodes.icLdtoken] = Ldtoken; + _handlers[(uint)OpCodes.icThrow] = Throw; + _handlers[(uint)OpCodes.icRethrow] = Rethrow; + _handlers[(uint)OpCodes.icCastclass] = Castclass; + _handlers[(uint)OpCodes.icIsinst] = Isinst; + _handlers[(uint)OpCodes.icCkfinite] = Ckfinite; + _handlers[(uint)OpCodes.icLocalloc] = Localloc; + } + + private void Push(BaseVariant value) + { + _stack.Push(value.ToStack()); + } + + private BaseVariant Pop() + { + return _stack.Pop(); + } + + private BaseVariant Peek() + { + return _stack.Peek(); + } + + private byte ReadByte() + { + byte res = Marshal.ReadByte(new IntPtr(_instance + _pos)); + _pos += sizeof(byte); + return res; + } + + private short ReadInt16() + { + short res = Marshal.ReadInt16(new IntPtr(_instance + _pos)); + _pos += sizeof(short); + return res; + } + + private int ReadInt32() + { + int res = Marshal.ReadInt32(new IntPtr(_instance + _pos)); + _pos += sizeof(int); + return res; + } + + private long ReadInt64() + { + long res = Marshal.ReadInt64(new IntPtr(_instance + _pos)); + _pos += sizeof(long); + return res; + } + + private float ReadSingle() + { + return BitConverter.ToSingle(BitConverter.GetBytes(ReadInt32()), 0); + } + + private double ReadDouble() + { + return BitConverter.ToDouble(BitConverter.GetBytes(ReadInt64()), 0); + } + + private void Initcatchblock() + { + var type = ReadByte(); + var tryBegin = ReadInt32(); + var tryEnd = ReadInt32(); + var handler = ReadInt32(); + var filter = ReadInt32(); + TryBlock tryBlock = null; + for (var i = 0; i < _tryBlocks.Count; i++) + { + var current = _tryBlocks[i]; + if (current.Begin() == tryBegin && current.End() == tryEnd) + { + tryBlock = current; + break; + } + } + if (tryBlock == null) + { + bool isInserted = false; + tryBlock = new TryBlock(tryBegin, tryEnd); + for (var i = 0; i < _tryBlocks.Count; i++) + { + var current = _tryBlocks[i]; + if (tryBlock.CompareTo(current) < 0) + { + _tryBlocks.Insert(i, tryBlock); + isInserted = true; + break; + } + } + if (!isInserted) + _tryBlocks.Add(tryBlock); + } + tryBlock.AddCatchBlock(type, handler, filter); + } + + private TypeCode CalcTypeCode(BaseVariant v1, BaseVariant v2) + { + var type1 = v1.CalcTypeCode(); + var type2 = v2.CalcTypeCode(); + if (type1 == TypeCode.Empty || type1 == TypeCode.Object || type2 == TypeCode.Empty || type2 == TypeCode.Object) + return TypeCode.Empty; + + // UInt32/UInt64 used for pointers + if (type1 == TypeCode.UInt32) + return (type2 == TypeCode.Int32) ? type1 : TypeCode.Empty; + if (type2 == TypeCode.UInt32) + return (type1 == TypeCode.Int32) ? type2 : TypeCode.Empty; + if (type1 == TypeCode.UInt64) + return (type2 == TypeCode.Int32 || type2 == TypeCode.Int64) ? type1 : TypeCode.Empty; + if (type2 == TypeCode.UInt64) + return (type1 == TypeCode.Int32 || type1 == TypeCode.Int64) ? type1 : TypeCode.Empty; + + if (type1 == TypeCode.Double || type2 == TypeCode.Double) + return TypeCode.Double; + if (type1 == TypeCode.Single || type2 == TypeCode.Single) + return TypeCode.Single; + if (type1 == TypeCode.Int64 || type2 == TypeCode.Int64) + return TypeCode.Int64; + return TypeCode.Int32; + } + + private BaseVariant Add(BaseVariant v1, BaseVariant v2, bool ovf, bool un) + { + var type = CalcTypeCode(v1, v2); + switch (type) + { + case TypeCode.Int32: + { + int value; + if (un) + { + var value1 = v1.ToUInt32(); + var value2 = v2.ToUInt32(); + value = ovf ? (int)checked(value1 + value2) : (int)(value1 + value2); + } + else + { + var value1 = v1.ToInt32(); + var value2 = v2.ToInt32(); + value = ovf ? checked(value1 + value2) : (value1 + value2); + } + return new IntVariant(value); + } + case TypeCode.Int64: + { + long value; + if (un) + { + var value1 = v1.ToUInt64(); + var value2 = v2.ToUInt64(); + value = ovf ? (long)checked(value1 + value2) : (long)(value1 + value2); + } + else + { + var value1 = v1.ToInt64(); + var value2 = v2.ToInt64(); + value = ovf ? checked(value1 + value2) : (value1 + value2); + } + return new LongVariant(value); + } + case TypeCode.Single: + { + var value1 = (un ? v1.ToUnsigned() : v1).ToSingle(); + var value2 = (un ? v2.ToUnsigned() : v2).ToSingle(); + return new SingleVariant(ovf ? checked(value1 + value2) : (value1 + value2)); + } + case TypeCode.Double: + { + var value1 = (un ? v1.ToUnsigned() : v1).ToDouble(); + var value2 = (un ? v2.ToUnsigned() : v2).ToDouble(); + return new DoubleVariant(ovf ? checked(value1 + value2) : (value1 + value2)); + } + case TypeCode.UInt32: + { + int value; + if (un) + { + var value1 = v1.ToUInt32(); + var value2 = v2.ToUInt32(); + value = ovf ? (int)checked(value1 + value2) : (int)(value1 + value2); + } + else + { + var value1 = v1.ToInt32(); + var value2 = v2.ToInt32(); + value = ovf ? checked(value1 + value2) : (value1 + value2); + } + PointerVariant v = v1.CalcTypeCode() == type ? (PointerVariant)v1 : (PointerVariant)v2; + unsafe + { + return new PointerVariant(Pointer.Box(new IntPtr(value).ToPointer(), v.Type()), v.Type()); + } + } + case TypeCode.UInt64: + { + long value; + if (un) + { + var value1 = v1.ToUInt64(); + var value2 = v2.ToUInt64(); + value = ovf ? (long)checked(value1 + value2) : (long)(value1 + value2); + } + else + { + var value1 = v1.ToInt64(); + var value2 = v2.ToInt64(); + value = ovf ? checked(value1 + value2) : (value1 + value2); + } + PointerVariant v = v1.CalcTypeCode() == type ? (PointerVariant)v1 : (PointerVariant)v2; + unsafe + { + return new PointerVariant(Pointer.Box(new IntPtr(value).ToPointer(), v.Type()), v.Type()); + } + } + } + throw new InvalidOperationException(); + } + + private BaseVariant Sub(BaseVariant v1, BaseVariant v2, bool ovf, bool un) + { + var type = CalcTypeCode(v1, v2); + switch (type) + { + case TypeCode.Int32: + { + int value; + if (un) + { + var value1 = v1.ToUInt32(); + var value2 = v2.ToUInt32(); + value = ovf ? (int)checked(value1 - value2) : (int)(value1 - value2); + } + else + { + var value1 = v1.ToInt32(); + var value2 = v2.ToInt32(); + value = ovf ? checked(value1 - value2) : (value1 - value2); + } + return new IntVariant(value); + } + case TypeCode.Int64: + { + long value; + if (un) + { + var value1 = v1.ToUInt64(); + var value2 = v2.ToUInt64(); + value = ovf ? (long)checked(value1 - value2) : (long)(value1 - value2); + } + else + { + var value1 = v1.ToInt64(); + var value2 = v2.ToInt64(); + value = ovf ? checked(value1 - value2) : (value1 - value2); + } + return new LongVariant(value); + } + case TypeCode.Single: + { + var value1 = (un ? v1.ToUnsigned() : v1).ToSingle(); + var value2 = (un ? v2.ToUnsigned() : v2).ToSingle(); + return new SingleVariant(ovf ? checked(value1 - value2) : (value1 - value2)); + } + case TypeCode.Double: + { + var value1 = (un ? v1.ToUnsigned() : v1).ToDouble(); + var value2 = (un ? v2.ToUnsigned() : v2).ToDouble(); + return new DoubleVariant(ovf ? checked(value1 - value2) : (value1 - value2)); + } + case TypeCode.UInt32: + { + int value; + if (un) + { + var value1 = v1.ToUInt32(); + var value2 = v2.ToUInt32(); + value = ovf ? (int)checked(value1 - value2) : (int)(value1 - value2); + } + else + { + var value1 = v1.ToInt32(); + var value2 = v2.ToInt32(); + value = ovf ? checked(value1 - value2) : (value1 - value2); + } + PointerVariant v = v1.CalcTypeCode() == type ? (PointerVariant)v1 : (PointerVariant)v2; + unsafe + { + return new PointerVariant(Pointer.Box(new IntPtr(value).ToPointer(), v.Type()), v.Type()); + } + } + case TypeCode.UInt64: + { + long value; + if (un) + { + var value1 = v1.ToUInt64(); + var value2 = v2.ToUInt64(); + value = ovf ? (long)checked(value1 - value2) : (long)(value1 - value2); + } + else + { + var value1 = v1.ToInt64(); + var value2 = v2.ToInt64(); + value = ovf ? checked(value1 - value2) : (value1 - value2); + } + PointerVariant v = v1.CalcTypeCode() == type ? (PointerVariant)v1 : (PointerVariant)v2; + unsafe + { + return new PointerVariant(Pointer.Box(new IntPtr(value).ToPointer(), v.Type()), v.Type()); + } + } + } + throw new InvalidOperationException(); + } + + private BaseVariant Mul(BaseVariant v1, BaseVariant v2, bool ovf, bool un) + { + var type = CalcTypeCode(v1, v2); + switch (type) + { + case TypeCode.Int32: + { + int value; + if (un) + { + var value1 = v1.ToUInt32(); + var value2 = v2.ToUInt32(); + value = ovf ? (int)checked(value1 * value2) : (int)(value1 * value2); + } + else + { + var value1 = v1.ToInt32(); + var value2 = v2.ToInt32(); + value = ovf ? checked(value1 * value2) : (value1 * value2); + } + return new IntVariant(value); + } + case TypeCode.Int64: + { + long value; + if (un) + { + var value1 = v1.ToUInt64(); + var value2 = v2.ToUInt64(); + value = ovf ? (long)checked(value1 * value2) : (long)(value1 * value2); + } + else + { + var value1 = v1.ToInt64(); + var value2 = v2.ToInt64(); + value = ovf ? checked(value1 * value2) : (value1 * value2); + } + return new LongVariant(value); + } + case TypeCode.Single: + { + var value1 = (un ? v1.ToUnsigned() : v1).ToSingle(); + var value2 = (un ? v2.ToUnsigned() : v2).ToSingle(); + return new DoubleVariant(ovf ? checked(value1 * value2) : (value1 * value2)); + } + case TypeCode.Double: + { + var value1 = (un ? v1.ToUnsigned() : v1).ToDouble(); + var value2 = (un ? v2.ToUnsigned() : v2).ToDouble(); + return new DoubleVariant(ovf ? checked(value1 * value2) : (value1 * value2)); + } + } + throw new InvalidOperationException(); + } + + private BaseVariant Div(BaseVariant v1, BaseVariant v2, bool un) + { + var type = CalcTypeCode(v1, v2); + switch (type) + { + case TypeCode.Int32: + { + int value; + if (un) + { + var value1 = v1.ToUInt32(); + var value2 = v2.ToUInt32(); + value = (int)(value1 / value2); + } + else + { + var value1 = v1.ToInt32(); + var value2 = v2.ToInt32(); + value = value1 / value2; + } + return new IntVariant(value); + } + case TypeCode.Int64: + { + long value; + if (un) + { + var value1 = v1.ToUInt64(); + var value2 = v2.ToUInt64(); + value = (long)(value1 / value2); + } + else + { + var value1 = v1.ToInt64(); + var value2 = v2.ToInt64(); + value = value1 / value2; + } + return new LongVariant(value); + } + case TypeCode.Single: + { + var value1 = (un ? v1.ToUnsigned() : v1).ToSingle(); + var value2 = (un ? v2.ToUnsigned() : v2).ToSingle(); + return new SingleVariant(value1 / value2); + } + case TypeCode.Double: + { + var value1 = (un ? v1.ToUnsigned() : v1).ToDouble(); + var value2 = (un ? v2.ToUnsigned() : v2).ToDouble(); + return new DoubleVariant(value1 / value2); + } + } + throw new InvalidOperationException(); + } + + private BaseVariant Rem(BaseVariant v1, BaseVariant v2, bool un) + { + var type1 = v1.CalcTypeCode(); + switch (type1) + { + case TypeCode.Int32: + if (un) + { + var value1 = v1.ToUInt32(); + var value2 = v2.ToUInt32(); + return new IntVariant((int)(value1 % value2)); + } else { + var value1 = v1.ToInt32(); + var value2 = v2.ToInt32(); + return new IntVariant(value1 % value2); + } + case TypeCode.Int64: + if (un) + { + var value1 = v1.ToUInt64(); + var value2 = v2.ToUInt64(); + return new LongVariant((long)(value1 % value2)); + } else { + var value1 = v1.ToInt64(); + var value2 = v2.ToInt64(); + return new LongVariant(value1 % value2); + } + } + throw new InvalidOperationException(); + } + + private BaseVariant Xor(BaseVariant v1, BaseVariant v2) + { + var type = CalcTypeCode(v1, v2); + switch (type) + { + case TypeCode.Int32: + { + var value1 = v1.ToInt32(); + var value2 = v2.ToInt32(); + return new IntVariant(value1 ^ value2); + } + case TypeCode.Int64: + { + var value1 = v1.ToInt64(); + var value2 = v2.ToInt64(); + return new LongVariant(value1 ^ value2); + } + case TypeCode.Single: + return new SingleVariant((IntPtr.Size == 4) ? float.NaN : (float)0); + case TypeCode.Double: + return new DoubleVariant((IntPtr.Size == 4) ? Double.NaN : (double)0); + } + throw new InvalidOperationException(); + } + + private BaseVariant Or(BaseVariant v1, BaseVariant v2) + { + var type = CalcTypeCode(v1, v2); + switch (type) + { + case TypeCode.Int32: + { + var value1 = v1.ToInt32(); + var value2 = v2.ToInt32(); + return new IntVariant(value1 | value2); + } + case TypeCode.Int64: + { + var value1 = v1.ToInt64(); + var value2 = v2.ToInt64(); + return new LongVariant(value1 | value2); + } + case TypeCode.Single: + return new SingleVariant((IntPtr.Size == 4) ? float.NaN : (float)0); + case TypeCode.Double: + return new DoubleVariant((IntPtr.Size == 4) ? Double.NaN : (double)0); + } + throw new InvalidOperationException(); + } + + private BaseVariant And(BaseVariant v1, BaseVariant v2) + { + var type = CalcTypeCode(v1, v2); + switch (type) + { + case TypeCode.Int32: + { + var value1 = v1.ToInt32(); + var value2 = v2.ToInt32(); + return new IntVariant(value1 & value2); + } + case TypeCode.Int64: + { + var value1 = v1.ToInt64(); + var value2 = v2.ToInt64(); + return new LongVariant(value1 & value2); + } + case TypeCode.Single: + return new SingleVariant((IntPtr.Size == 4) ? float.NaN : (float)0); + case TypeCode.Double: + return new DoubleVariant((IntPtr.Size == 4) ? Double.NaN : (double)0); + } + throw new InvalidOperationException(); + } + + private int Compare(BaseVariant v1, BaseVariant v2, bool un, int def) + { + var res = def; + var type1 = v1.CalcTypeCode(); + var type2 = v2.CalcTypeCode(); + if (type1 == TypeCode.Object || type2 == TypeCode.Object) + { + var obj1 = v1.Value(); + var obj2 = v2.Value(); + if (obj1 == obj2) + return 0; + return (obj2 == null) ? 1 : -1; + } + else if (type1 == TypeCode.Double || type2 == TypeCode.Double) + res = v1.ToDouble().CompareTo(v2.ToDouble()); + else if (type1 == TypeCode.Single || type2 == TypeCode.Single) + res = v1.ToSingle().CompareTo(v2.ToSingle()); + else if (type1 == TypeCode.Int64 || type2 == TypeCode.Int64) + res = un ? v1.ToUInt64().CompareTo(v2.ToUInt64()) : v1.ToInt64().CompareTo(v2.ToInt64()); + else if (type1 == TypeCode.Int32 || type2 == TypeCode.Int32) + res = un ? v1.ToUInt32().CompareTo(v2.ToUInt32()) : v1.ToInt32().CompareTo(v2.ToInt32()); + + if (res < 0) + res = -1; + else if (res > 0) + res = 1; + return res; + } + + private BaseVariant Not(BaseVariant v) + { + switch (v.CalcTypeCode()) + { + case TypeCode.Int32: + return new IntVariant(~v.ToInt32()); + case TypeCode.Int64: + return new LongVariant(~v.ToInt64()); + } + throw new InvalidOperationException(); + } + + private BaseVariant Neg(BaseVariant v) + { + switch (v.CalcTypeCode()) + { + case TypeCode.Int32: + return new IntVariant(-v.ToInt32()); + case TypeCode.Int64: + return new LongVariant(-v.ToInt64()); + case TypeCode.Single: + return new SingleVariant(-v.ToSingle()); + case TypeCode.Double: + return new DoubleVariant(-v.ToDouble()); + } + throw new InvalidOperationException(); + } + + private BaseVariant Shr(BaseVariant v1, BaseVariant v2, bool un) + { + var type = v1.CalcTypeCode(); + switch (type) + { + case TypeCode.Int32: + if (un) + { + var value1 = v1.ToUInt32(); + var value2 = v2.ToInt32(); + return new IntVariant((int)(value1 >> value2)); + } else { + var value1 = v1.ToInt32(); + var value2 = v2.ToInt32(); + return new IntVariant(value1 >> value2); + } + case TypeCode.Int64: + if (un) + { + var value1 = v1.ToUInt64(); + var value2 = v2.ToInt32(); + return new LongVariant((long)(value1 >> value2)); + } else { + var value1 = v1.ToInt64(); + var value2 = v2.ToInt32(); + return new LongVariant(value1 >> value2); + } + } + throw new InvalidOperationException(); + } + + private BaseVariant Shl(BaseVariant v1, BaseVariant v2) + { + var type = v1.CalcTypeCode(); + switch (type) + { + case TypeCode.Int32: + { + var value1 = v1.ToInt32(); + var value2 = v2.ToInt32(); + return new IntVariant(value1 << value2); + } + case TypeCode.Int64: + { + var value1 = v1.ToInt64(); + var value2 = v2.ToInt32(); + return new LongVariant(value1 << value2); + } + } + throw new InvalidOperationException(); + } + + private BaseVariant Convert(object obj, Type t) + { + BaseVariant v = obj as BaseVariant; + + if (t.IsEnum) + { + if (v != null) + obj = v.Value(); + if (obj != null && !(obj is Enum)) + obj = Enum.ToObject(t, obj); + return new EnumVariant(obj == null ? (Enum)Activator.CreateInstance(t) : (Enum)obj); + } + + switch (Type.GetTypeCode(t)) + { + case TypeCode.Boolean: + return new BoolVariant(v != null ? v.ToBoolean() : System.Convert.ToBoolean(obj)); + case TypeCode.Char: + return new CharVariant(v != null ? v.ToChar() : System.Convert.ToChar(obj)); + case TypeCode.SByte: + return new SbyteVariant(v != null ? v.ToSByte() : System.Convert.ToSByte(obj)); + case TypeCode.Byte: + return new ByteVariant(v != null ? v.ToByte() : System.Convert.ToByte(obj)); + case TypeCode.Int16: + return new ShortVariant(v != null ? v.ToInt16() : System.Convert.ToInt16(obj)); + case TypeCode.UInt16: + return new UshortVariant(v != null ? v.ToUInt16() : System.Convert.ToUInt16(obj)); + case TypeCode.Int32: + return new IntVariant(v != null ? v.ToInt32() : System.Convert.ToInt32(obj)); + case TypeCode.UInt32: + return new UintVariant(v != null ? v.ToUInt32() : System.Convert.ToUInt32(obj)); + case TypeCode.Int64: + return new LongVariant(v != null ? v.ToInt64() : System.Convert.ToInt64(obj)); + case TypeCode.UInt64: + return new UlongVariant(v != null ? v.ToUInt64() : System.Convert.ToUInt64(obj)); + case TypeCode.Single: + return new SingleVariant(v != null ? v.ToSingle() : System.Convert.ToSingle(obj)); + case TypeCode.Double: + return new DoubleVariant(v != null ? v.ToDouble() : System.Convert.ToDouble(obj)); + case TypeCode.String: + return new StringVariant(v != null ? v.ToString() : (string)obj); + } + + if (t == typeof(IntPtr)) + { + if (v != null) + return new IntPtrVariant(v.ToIntPtr()); + return new IntPtrVariant(obj != null ? (IntPtr)obj : IntPtr.Zero); + } + + if (t == typeof(UIntPtr)) + { + if (v != null) + return new UIntPtrVariant(v.ToUIntPtr()); + return new UIntPtrVariant(obj != null ? (UIntPtr)obj : UIntPtr.Zero); + } + + if (t.IsValueType) + { + if (v != null) + return new ValueTypeVariant(v.Value()); + return new ValueTypeVariant(obj == null ? Activator.CreateInstance(t) : obj); + } + + if (t.IsArray) + return new ArrayVariant(v != null ? (Array)v.Value() : (Array)obj); + + if (t.IsPointer) + { + unsafe + { + if (v != null) + return new PointerVariant(Pointer.Box(v.ToPointer(), t), t); + return new PointerVariant(Pointer.Box(obj != null ? Pointer.Unbox(obj) : null, t), t); + } + } + + return new ObjectVariant(v != null ? v.Value() : obj); + } + + string GetString(int token) + { + lock (_cache) + { + object stored; + if (_cache.TryGetValue(token, out stored)) + return (string)stored; + else + { + var str = _module.ResolveString(token); + _cache.Add(token, str); + return str; + } + } + } + + private Type GetType(int token) + { + lock (_cache) + { + object stored; + if (_cache.TryGetValue(token, out stored)) + return (Type)stored; + else + { + var type = _module.ResolveType(token); + _cache.Add(token, type); + return type; + } + } + } + + private MethodBase GetMethod(int token) + { + lock (_cache) + { + object stored; + if (_cache.TryGetValue(token, out stored)) + return (MethodBase)stored; + else + { + var method = _module.ResolveMethod(token); + _cache.Add(token, method); + return method; + } + } + } + + private FieldInfo GetField(int token) + { + lock (_cache) + { + object stored; + if (_cache.TryGetValue(token, out stored)) + return (FieldInfo)stored; + else + { + var field = _module.ResolveField(token); + _cache.Add(token, field); + return field; + } + } + } + + private BaseVariant Newobj(MethodBase method) + { + var parameters = method.GetParameters(); + var refs = new Dictionary<int, BaseVariant>(); + var args = new object[parameters.Length]; + for (var i = parameters.Length - 1; i >= 0; i--) + { + var v = Pop(); + if (v.IsReference()) + refs[i] = v; + args[i] = Convert(v, parameters[i].ParameterType).Value(); + } + var res = ((ConstructorInfo)method).Invoke(args); + foreach (var r in refs) + { + r.Value.SetValue(args[r.Key]); + } + return Convert(res, method.DeclaringType); + } + + private bool IsFilteredMethod(MethodBase method, object obj, ref object result, object[] args) + { + var t = method.DeclaringType; + if (t == null) + return false; + + if (Nullable.GetUnderlyingType(t) != null) + { + if (string.Equals(method.Name, "get_HasValue", StringComparison.Ordinal)) + { + result = (obj != null); + return true; + } + else if (string.Equals(method.Name, "get_Value", StringComparison.Ordinal)) + { + if (obj == null) + throw new InvalidOperationException(); + result = obj; + return true; + } + else if (method.Name.Equals("GetValueOrDefault", StringComparison.Ordinal)) + { + if (obj == null) + obj = Activator.CreateInstance(Nullable.GetUnderlyingType(method.DeclaringType)); + result = obj; + return true; + } + } + return false; + } + + private BaseVariant Call(MethodBase method, bool virt) + { + BindingFlags invokeFlags; +#if NETCOREAPP + invokeFlags = BindingFlags.DoNotWrapExceptions; +#else + invokeFlags = BindingFlags.Default; +#endif + + var info = method as MethodInfo; + var parameters = method.GetParameters(); + var refs = new Dictionary<int, BaseVariant>(); + var args = new object[parameters.Length]; + BaseVariant v; + for (var i = parameters.Length - 1; i >= 0; i--) + { + v = Pop(); + if (v.IsReference()) + refs[i] = v; + args[i] = Convert(v, parameters[i].ParameterType).Value(); + } + v = method.IsStatic ? null : Pop(); + object obj = v?.Value() ?? null; + if (virt && obj == null) + throw new NullReferenceException(); + object res = null; + if (method.IsConstructor && method.DeclaringType.IsValueType) + { + obj = Activator.CreateInstance(method.DeclaringType, invokeFlags, null, args, null); + if (v != null && v.IsReference()) + v.SetValue(Convert(obj, method.DeclaringType).Value()); + } + else if (!IsFilteredMethod(method, obj, ref res, args)) + { + if (!virt && method.IsVirtual && !method.IsFinal) + { + DynamicMethod dynamicMethod; + var paramValues = new object[parameters.Length + 1]; + paramValues[0] = obj; + for (var i = 0; i < parameters.Length; i++) + { + paramValues[i + 1] = args[i]; + } + lock (_dynamicMethodCache) + { + if (!_dynamicMethodCache.TryGetValue(method, out dynamicMethod)) + { + var paramTypes = new Type[paramValues.Length]; + paramTypes[0] = method.DeclaringType; + for (var i = 0; i < parameters.Length; i++) + { + paramTypes[i + 1] = parameters[i].ParameterType; + } + + dynamicMethod = new DynamicMethod("", info != null && info.ReturnType != typeof(void) ? info.ReturnType : null, paramTypes, typeof(VirtualMachine).Module, true); + var gen = dynamicMethod.GetILGenerator(); + gen.Emit(v.IsReference() ? System.Reflection.Emit.OpCodes.Ldarga : System.Reflection.Emit.OpCodes.Ldarg, 0); + for (var i = 1; i < paramTypes.Length; i++) + { + gen.Emit(refs.ContainsKey(i - 1) ? System.Reflection.Emit.OpCodes.Ldarga : System.Reflection.Emit.OpCodes.Ldarg, i); + } + gen.Emit(System.Reflection.Emit.OpCodes.Call, info); + gen.Emit(System.Reflection.Emit.OpCodes.Ret); + + _dynamicMethodCache[method] = dynamicMethod; + } + } + res = dynamicMethod.Invoke(null, invokeFlags, null, paramValues, null); + foreach (var r in refs) + { + r.Value.SetValue(paramValues[r.Key + 1]); + } + refs.Clear(); + } + else + { + res = method.Invoke(obj, invokeFlags, null, args, null); + } + } + foreach (var r in refs) + { + r.Value.SetValue(args[r.Key]); + } + return (info != null && info.ReturnType != typeof(void)) ? Convert(res, info.ReturnType) : null; + } + + private BaseVariant Callvm(int pos, bool virt) + { + var oldPos = _pos; + _pos = pos; + var parameterCount = (ushort)ReadInt16(); + var refs = new Dictionary<int, BaseVariant>(); + object[] args = null; + if (parameterCount > 0) + { + args = new object[parameterCount]; + for (var i = parameterCount - 1; i >= 0; i--) + { + BaseVariant v = Pop(); + if (v.IsReference()) + refs[i] = v; + args[i] = Convert(v, GetType(ReadInt32())).Value(); + } + } + var returnToken = ReadInt32(); + pos = _pos; + _pos = oldPos; + if (virt && (args == null || args[0] == null)) + throw new NullReferenceException(); + object res = new VirtualMachine().Invoke(args, pos); + foreach (var r in refs) + { + r.Value.SetValue(args[r.Key]); + } + if (returnToken != 0) + { + var returnType = GetType(returnToken); + if (returnType != typeof(void)) + return Convert(res, returnType); + } + return null; + } + + private bool IsInst(object obj, Type t) + { + if (obj == null) + return true; + var t2 = obj.GetType(); + if (t2 == t || t.IsAssignableFrom(t2)) + return true; + return false; + } + + private void Unwind() + { + _stack.Clear(); + _finallyStack.Clear(); + while (_tryStack.Count != 0) + { + var catchBlocks = _tryStack.Peek().CatchBlocks(); + int startIndex = (_filterBlock == null) ? 0 : catchBlocks.IndexOf(_filterBlock) + 1; + _filterBlock = null; + for (var i = startIndex; i < catchBlocks.Count; i++) + { + var current = catchBlocks[i]; + switch (current.Type()) + { + case 0: + var type = _exception.GetType(); + var type2 = GetType(current.Filter()); + if (type == type2 || type.IsSubclassOf(type2)) + { + _tryStack.Pop(); + _stack.Push(new ObjectVariant(_exception)); + _pos = current.Handler(); + return; + } + break; + case 1: + _filterBlock = current; + _stack.Push(new ObjectVariant(_exception)); + _pos = current.Filter(); + return; + } + } + + _tryStack.Pop(); + for (var i = catchBlocks.Count; i > 0; i--) + { + var current = catchBlocks[i - 1]; + if (current.Type() == 2 || current.Type() == 4) + _finallyStack.Push(current.Handler()); + } + if (_finallyStack.Count != 0) + { + _pos = _finallyStack.Pop(); + return; + } + } + + throw _exception; + } + + private void Initarg() + { + var type = GetType(Pop().ToInt32()); + var r = Pop(); + var v = Pop(); + if (r.IsReference()) + v = new ArgReferenceVariant(Convert(v.Value(), type), r); + else if (r.ToInt32() == 0) + v = Convert(v.Value(), type); + else + v = new NullReferenceVariant(type); + _args.Add(v); + } + + private void Entertry() + { + var i = Pop().ToInt32(); + foreach (var current in _tryBlocks) + { + if (current.Begin() == i) + _tryStack.Push(current); + } + } + + private void Ldc_i4() + { + Push(new IntVariant(ReadInt32())); + } + + private void Ldc_i8() + { + Push(new LongVariant(ReadInt64())); + } + + private void Ldc_r4() + { + Push(new SingleVariant(ReadSingle())); + } + + private void Ldc_r8() + { + Push(new DoubleVariant(ReadDouble())); + } + + private void Ldnull() + { + Push(new ObjectVariant(null)); + } + + private void Ldstr() + { + Push(new StringVariant(GetString(Pop().ToInt32()))); + } + + private void Dup() + { + Push(Peek().Clone()); + } + + private void Add_() + { + var v1 = Pop(); + var v2 = Pop(); + Push(Add(v1, v2, false, false)); + } + + private void Add_ovf() + { + var v1 = Pop(); + var v2 = Pop(); + Push(Add(v1, v2, true, false)); + } + + private void Add_ovf_un() + { + var v1 = Pop(); + var v2 = Pop(); + Push(Add(v1, v2, true, true)); + } + + private void Sub_() + { + var v2 = Pop(); + var v1 = Pop(); + Push(Sub(v1, v2, false, false)); + } + + private void Sub_ovf() + { + var v2 = Pop(); + var v1 = Pop(); + Push(Sub(v1, v2, true, false)); + } + + private void Sub_ovf_un() + { + var v2 = Pop(); + var v1 = Pop(); + Push(Sub(v1, v2, true, true)); + } + + private void Mul_() + { + var v2 = Pop(); + var v1 = Pop(); + Push(Mul(v1, v2, false, false)); + } + + private void Mul_ovf() + { + var v2 = Pop(); + var v1 = Pop(); + Push(Mul(v1, v2, true, false)); + } + + private void Mul_ovf_un() + { + var v2 = Pop(); + var v1 = Pop(); + Push(Mul(v1, v2, true, true)); + } + + private void Div_() + { + var v2 = Pop(); + var v1 = Pop(); + Push(Div(v1, v2, false)); + } + + private void Div_un() + { + var v2 = Pop(); + var v1 = Pop(); + Push(Div(v1, v2, true)); + } + + private void Rem_() + { + var v2 = Pop(); + var v1 = Pop(); + Push(Rem(v1, v2, false)); + } + + private void Rem_un() + { + var v2 = Pop(); + var v1 = Pop(); + Push(Rem(v1, v2, true)); + } + + private void And_() + { + var v2 = Pop(); + var v1 = Pop(); + Push(And(v1, v2)); + } + + private void Or_() + { + var v2 = Pop(); + var v1 = Pop(); + Push(Or(v1, v2)); + } + + private void Xor_() + { + var v2 = Pop(); + var v1 = Pop(); + Push(Xor(v1, v2)); + } + + private void Not_() + { + var v = Pop(); + Push(Not(v)); + } + + private void Neg_() + { + var v = Pop(); + Push(Neg(v)); + } + + private void Shr_() + { + var v2 = Pop(); + var v1 = Pop(); + Push(Shr(v1, v2, false)); + } + + private void Shr_un() + { + var v2 = Pop(); + var v1 = Pop(); + Push(Shr(v1, v2, true)); + } + + private void Shl_() + { + var v2 = Pop(); + var v1 = Pop(); + Push(Shl(v1, v2)); + } + + private void Conv() + { + var type = GetType(Pop().ToInt32()); + Push(Convert(Pop(), type)); + } + + private void Conv_ovf() + { + var type = GetType(Pop().ToInt32()); + Push(Convert(Pop().Conv_ovf(type, false), type)); + } + + private void Conv_ovf_un() + { + var type = GetType(Pop().ToInt32()); + Push(Convert(Pop().Conv_ovf(type, true), type)); + } + + private void Sizeof() + { + var type = GetType(Pop().ToInt32()); + var dynamicMethod = new DynamicMethod("", typeof(int), null, typeof(VirtualMachine).Module, true); + var gen = dynamicMethod.GetILGenerator(); + gen.Emit(System.Reflection.Emit.OpCodes.Sizeof, type); + gen.Emit(System.Reflection.Emit.OpCodes.Ret); + + Push(new IntVariant((int)dynamicMethod.Invoke(null, null))); + } + + private void Ldind() + { + var type = GetType(Pop().ToInt32()); + var v = Pop(); + if (!v.IsReference()) + { + if (v.Value() is Pointer) + unsafe { v = new PointerReference(new IntPtr(Pointer.Unbox(v.Value())), type); } + else + throw new ArgumentException(); + } + Push(Convert(v, type)); + } + + private void Ldfld() + { + var field = GetField(Pop().ToInt32()); + var v = Pop(); + object obj; + if (v.Type().IsPointer) + obj = Marshal.PtrToStructure(v.ToIntPtr(), v.Type().GetElementType()); + else + obj = v.Value(); + Push(Convert(field.GetValue(obj), field.FieldType)); + } + + private void Ldflda() + { + var field = GetField(Pop().ToInt32()); + var v = Pop(); + Push(new FieldReferenceVariant(field, v)); + } + + private void Stfld() + { + var field = GetField(Pop().ToInt32()); + var v = Pop(); + var baseVariant = Pop(); + var obj = baseVariant.Value(); + baseVariant.SetFieldValue(field, Convert(v, field.FieldType).Value()); + } + + private void Stsfld() + { + var field = GetField(Pop().ToInt32()); + var v = Pop(); + field.SetValue(null, Convert(v, field.FieldType).Value()); + } + + private void Stind() + { + var type = GetType(Pop().ToInt32()); + var v2 = Pop(); + var v1 = Pop(); + v2 = Convert(v2, type); + if (v1.IsReference()) + v2 = Convert(v2, v1.Type()); + else { + if (v1.Value() is Pointer) + unsafe { v1 = new PointerReference(new IntPtr(Pointer.Unbox(v1.Value())), type); } + else + throw new ArgumentException(); + } + v1.SetValue(v2.Value()); + } + + private void Ldarg() + { + Push(_args[ReadInt16()].Clone()); + } + + private void Ldarga() + { + var v = _args[ReadInt16()]; + if (v.IsReference()) + throw new ArgumentException(); + Push(new ReferenceVariant(v)); + } + + private void Starg() + { + var v2 = Pop(); + int index = ReadInt16(); + var v1 = _args[index]; + if (v1.IsReference()) + { + if (!v2.IsReference()) + throw new ArgumentException(); + _args[index] = v2; + } + else + { + v1.SetValue(Convert(v2, v1.Type()).Value()); + } + } + + private void Constrained() + { + _constrained = GetType(Pop().ToInt32()); + } + + private void Call_() + { + var method = GetMethod(Pop().ToInt32()); + var v = Call(method, false); + if (v != null) + Push(v); + } + + private void Callvirt() + { + var method = GetMethod(Pop().ToInt32()); + if (_constrained != null) + { + var parameters = method.GetParameters(); + var types = new Type[parameters.Length]; + var num = 0; + foreach (var param in parameters) + { + types[num++] = param.ParameterType; + } + var new_method = _constrained.GetMethod(method.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.GetProperty | BindingFlags.SetProperty, null, types, null); + if (new_method != null) + method = new_method; + _constrained = null; + } + var v = Call(method, true); + if (v != null) + Push(v); + } + + private void Calli() + { + var method = Pop().Value() as MethodBase; + if (method == null) + throw new ArgumentException(); + var v = Call(method, false); + if (v != null) + Push(v); + } + + private void Callvm_() + { + var v = Callvm(Pop().ToInt32(), false); + if (v != null) + Push(v); + } + + private void Callvmvirt() + { + var v = Callvm(Pop().ToInt32(), true); + if (v != null) + Push(v); + } + + private void Newobj_() + { + var method = GetMethod(Pop().ToInt32()); + var v = Newobj(method); + if (v != null) + Push(v); + } + + private void Initobj() + { + var type = GetType(Pop().ToInt32()); + var v = Pop(); + object obj = null; + if (type.IsValueType) + { + if (Nullable.GetUnderlyingType(type) == null) + obj = FormatterServices.GetUninitializedObject(type); + } + v.SetValue(obj); + } + + private void Cmp() + { + var def = Pop().ToInt32(); + var v2 = Pop(); + var v1 = Pop(); + Push(new IntVariant(Compare(v1, v2, false, def))); + } + + private void Cmp_un() + { + var def = Pop().ToInt32(); + var v2 = Pop(); + var v1 = Pop(); + Push(new IntVariant(Compare(v1, v2, true, def))); + } + + private void Newarr() + { + var type = GetType(Pop().ToInt32()); + Push(new ArrayVariant(Array.CreateInstance(type, Pop().ToInt32()))); + } + + private void Stelem() + { + var type = GetType(Pop().ToInt32()); + var v2 = Pop(); + var v1 = Pop(); + var array = Pop().Value() as Array; + if (array == null) + throw new ArgumentException(); + array.SetValue(Convert(Convert(v2, type), array.GetType().GetElementType()).Value(), v1.ToInt32()); + } + + private void Ldelem() + { + var type = GetType(Pop().ToInt32()); + var v = Pop(); + var array = Pop().Value() as Array; + if (array == null) + throw new ArgumentException(); + Push(Convert(array.GetValue(v.ToInt32()), type)); + } + + private void Ldlen() + { + var array = Pop().Value() as Array; + if (array == null) + throw new ArgumentException(); + Push(new IntVariant(array.Length)); + } + + private void Ldelema() + { + var v = Pop(); + var array = Pop().Value() as Array; + if (array == null) + throw new ArgumentException(); + Push(new ArrayElementVariant(array, v.ToInt32())); + } + + private void Ldftn() + { + Push(new MethodVariant(GetMethod(Pop().ToInt32()))); + } + + private void Ldvirtftn() + { + var method = GetMethod(Pop().ToInt32()); + var type = Pop().Value().GetType(); + var declaringType = method.DeclaringType; + var parameters = method.GetParameters(); + var types = new Type[parameters.Length]; + var num = 0; + foreach (var param in parameters) + { + types[num++] = param.ParameterType; + } + while (type != null && type != declaringType) + { + var new_method = type.GetMethod(method.Name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.SetProperty | BindingFlags.ExactBinding, null, CallingConventions.Any, types, null); + if (new_method != null && new_method.GetBaseDefinition() == method) + { + method = new_method; + break; + } + type = type.BaseType; + } + Push(new MethodVariant(method)); + } + + private void Br() + { + _pos = Pop().ToInt32(); + } + + private void Pop_() + { + Pop(); + } + + private void Leave() + { + _finallyStack.Push(Pop().ToInt32()); + var offset = Pop().ToInt32(); + while (_tryStack.Count != 0 && offset > _tryStack.Peek().End()) + { + var catchBlocks = _tryStack.Pop().CatchBlocks(); + for (var i = catchBlocks.Count; i > 0; i--) + { + var current = catchBlocks[i - 1]; + if (current.Type() == 2) + _finallyStack.Push(current.Handler()); + } + } + + _exception = null; + _stack.Clear(); + _pos = _finallyStack.Pop(); + } + + private void Endfinally() + { + if (_exception == null) + { + _pos = _finallyStack.Pop(); + return; + } + Unwind(); + } + + private void Endfilter() + { + if (Pop().ToInt32() != 0) + { + _tryStack.Pop(); + _stack.Push(new ObjectVariant(_exception)); + _pos = _filterBlock.Handler(); + _filterBlock = null; + return; + } + Unwind(); + } + + private void Box() + { + var type = GetType(Pop().ToInt32()); + Push(new ObjectVariant(Convert(Pop(), type).Value())); + } + + private void Unbox() + { + var type = GetType(Pop().ToInt32()); + Push(Convert(Pop().Value(), type)); + } + + private void Unbox_any() + { + var type = GetType(Pop().ToInt32()); + var v = Pop(); + var obj = v.Value(); + if (obj == null) + throw new NullReferenceException(); + + if (type.IsValueType) + { + if (type != obj.GetType()) + throw new InvalidCastException(); + Push(Convert(obj, type)); + } + else switch (Type.GetTypeCode(type)) + { + case TypeCode.Boolean: + Push(new BoolVariant((bool)obj)); + break; + case TypeCode.Char: + Push(new CharVariant((char)obj)); + break; + case TypeCode.SByte: + Push(new SbyteVariant((sbyte)obj)); + break; + case TypeCode.Byte: + Push(new ByteVariant((byte)obj)); + break; + case TypeCode.Int16: + Push(new ShortVariant((short)obj)); + break; + case TypeCode.UInt16: + Push(new UshortVariant((ushort)obj)); + break; + case TypeCode.Int32: + Push(new IntVariant((int)obj)); + break; + case TypeCode.UInt32: + Push(new UintVariant((uint)obj)); + break; + case TypeCode.Int64: + Push(new LongVariant((long)obj)); + break; + case TypeCode.UInt64: + Push(new UlongVariant((ulong)obj)); + break; + case TypeCode.Single: + Push(new SingleVariant((float)obj)); + break; + case TypeCode.Double: + Push(new DoubleVariant((double)obj)); + break; + default: + throw new InvalidCastException(); + } + } + + private void Ldmem_i4() + { + Push(new IntVariant(Marshal.ReadInt32(new IntPtr(_instance + Pop().ToUInt32())))); + } + + private void Ldtoken() + { + var i = Pop().ToInt32(); + switch (i >> 24) + { + case 04: + Push(new ValueTypeVariant(_module.ModuleHandle.ResolveFieldHandle(i))); + break; + case 0x01: + case 0x02: + case 0x1b: + Push(new ValueTypeVariant(_module.ModuleHandle.ResolveTypeHandle(i))); + break; + case 0x06: + case 0x2b: + Push(new ValueTypeVariant(_module.ModuleHandle.ResolveMethodHandle(i))); + break; + case 0x0a: + try + { + Push(new ValueTypeVariant(_module.ModuleHandle.ResolveFieldHandle(i))); + } + catch + { + Push(new ValueTypeVariant(_module.ModuleHandle.ResolveMethodHandle(i))); + } + break; + default: + throw new InvalidOperationException(); + } + } + + private void Throw() + { + var e = Pop().Value() as Exception; + if (e == null) + throw new ArgumentException(); + throw e; + } + + private void Rethrow() + { + if (_exception == null) + throw new InvalidOperationException(); + throw _exception; + } + + private void Castclass() + { + var type = GetType(Pop().ToInt32()); + var v = Pop(); + if (!IsInst(v.Value(), type)) + throw new InvalidCastException(); + Push(v); + } + + private void Isinst() + { + var type = GetType(Pop().ToInt32()); + var v = Pop(); + if (!IsInst(v.Value(), type)) + v = new ObjectVariant(null); + Push(v); + } + + private void Ckfinite() + { + var v = Pop(); + if (v.Value() is IConvertible) + { + var d = v.ToDouble(); + if (double.IsNaN(d) || double.IsInfinity(d)) + throw new OverflowException(); + } + else + { + v = new DoubleVariant(double.NaN); + } + Push(v); + } + + private void Localloc() + { + var ptr = Marshal.AllocHGlobal(Pop().ToIntPtr()); + _localloc.Add(ptr); + unsafe { + Push(new ObjectVariant(Pointer.Box(ptr.ToPointer(), typeof(void*)))); + } + } + + private void FreeAllLocalloc() + { + foreach (var ptr in _localloc) + { + Marshal.FreeHGlobal(ptr); + } + } + + public object Invoke(object[] args, int pos) + { + _pos = pos; + Push(new ArrayVariant(args)); + try + { + while (true) + { + try + { + _handlers[ReadByte()](); + if (_pos == 0) + break; + } + catch (Exception e) + { + if (_filterBlock == null) + _exception = e; + Unwind(); + } + } + return Pop().Value(); + } + finally + { + FreeAllLocalloc(); + } + } + } +}
\ No newline at end of file diff --git a/runtime/VMProtect.Runtime/Win32.cs b/runtime/VMProtect.Runtime/Win32.cs new file mode 100644 index 0000000..e989344 --- /dev/null +++ b/runtime/VMProtect.Runtime/Win32.cs @@ -0,0 +1,825 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; + +// ReSharper disable once CheckNamespace +namespace VMProtect +{ + public enum MessageBoxButtons : uint + { + OK, + OKCancel, + AbortRetryIgnore, + YesNoCancel, + YesNo, + RetryCancel, + CancelTryAgainContinue + } + + public enum MessageBoxIcon : uint + { + Asterisk = 0x40, + Error = 0x10, + Exclamation = 0x30, + Hand = 0x10, + Information = 0x40, + None = 0, + Question = 0x20, + Stop = 0x10, + Warning = 0x30, + UserIcon = 0x80 + } + + + internal static class Win32 + { + [Flags()] + public enum AllocationType : uint + { + Commit = 0x1000, + Reserve = 0x2000, + } + + [Flags()] + public enum FreeType : uint + { + Release = 0x8000, + } + + [Flags()] + public enum MemoryProtection : uint + { + NoAccess = 0x01, + ReadOnly = 0x02, + ReadWrite = 0x04, + WriteCopy = 0x08, + Execute = 0x10, + ExecuteRead = 0x20, + ExecuteReadWrite = 0x40, + Guard = 0x100 + } + + [Flags()] + public enum MapAccess : uint + { + Copy = 0x0001, + Write = 0x0002, + Read = 0x0004, + AllAccess = 0x001f + } + + [Flags()] + public enum SectionType : uint + { + Execute = 0x20000000, + Read = 0x40000000, + Write = 0x80000000 + } + + [StructLayout(LayoutKind.Sequential)] + public struct UNICODE_STRING + { + public readonly ushort Length; + public readonly ushort MaximumLength; + private readonly IntPtr Buffer; + + public UNICODE_STRING(string str) + { + if (str == null) + { + Length = 0; + MaximumLength = 0; + Buffer = IntPtr.Zero; + } + else + { + Length = (ushort)(str.Length * UnicodeEncoding.CharSize); + MaximumLength = (ushort)(Length + UnicodeEncoding.CharSize); + Buffer = Marshal.StringToHGlobalUni(str); + } + } + + public void Dispose() + { + if (Buffer != IntPtr.Zero) + Marshal.FreeHGlobal(Buffer); + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct OBJECT_ATTRIBUTES + { + public readonly uint Length; + public readonly IntPtr RootDirectory; + public readonly IntPtr ObjectName; + public readonly uint Attributes; + public readonly IntPtr SecurityDescriptor; + public readonly IntPtr SecurityQualityOfService; + + public OBJECT_ATTRIBUTES(UNICODE_STRING name, uint attrs) + { + Length = (uint)Marshal.SizeOf(typeof(OBJECT_ATTRIBUTES)); + RootDirectory = IntPtr.Zero; + ObjectName = IntPtr.Zero; + Attributes = attrs; + SecurityDescriptor = IntPtr.Zero; + SecurityQualityOfService = IntPtr.Zero; + + ObjectName = Marshal.AllocHGlobal(Marshal.SizeOf(name)); + Marshal.StructureToPtr(name, ObjectName, false); + } + + public void Dispose() + { + Marshal.FreeHGlobal(ObjectName); + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct IO_STATUS_BLOCK + { + public uint Status; + public IntPtr Information; + } + + [StructLayout(LayoutKind.Sequential)] + public struct LARGE_INTEGER + { + public uint LowPart; + public uint HighPart; + } + + public enum HardErrorResponse + { + ReturnToCaller, + NotHandled, + Abort, Cancel, + Ignore, + No, + Ok, + Retry, + Yes + } + + public enum Values : uint + { + GENERIC_READ = 0x80000000, + FILE_SHARE_READ = 0x00000001, + FILE_SHARE_WRITE = 0x00000002, + FILE_READ_ATTRIBUTES = 0x00000080, + SYNCHRONIZE = 0x00100000, + SECTION_QUERY = 0x0001, + SECTION_MAP_WRITE = 0x0002, + SECTION_MAP_READ = 0x0004, + SECTION_MAP_EXECUTE = 0x0008, + SEC_COMMIT = 0x8000000, + FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020, + FILE_NON_DIRECTORY_FILE = 0x00000040, + } + + public static readonly IntPtr InvalidHandleValue = new IntPtr(-1); + public static readonly IntPtr NullHandle = IntPtr.Zero; + public static readonly IntPtr CurrentProcess = new IntPtr(-1); + public static readonly IntPtr CurrentThread = new IntPtr(-2); + + [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] + private delegate uint tNtQueryInformationProcess(IntPtr ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, + IntPtr ProcessInformation, int ProcessInformationLength, out uint ReturnLength); + [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] + private delegate uint tNtSetInformationThread(IntPtr ThreadHandle, THREADINFOCLASS ThreadInformationClass, IntPtr ThreadInformation, + uint ThreadInformationLength); + [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] + private delegate uint tEnumSystemFirmwareTables(uint firmwareTableProviderSignature, IntPtr firmwareTableBuffer, uint bufferSize); + [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] + private delegate uint tGetSystemFirmwareTable(uint firmwareTableProviderSignature, uint firmwareTableID, IntPtr firmwareTableBuffer, uint bufferSize); + [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] + private delegate uint tNtClose(IntPtr Handle); + [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] + private delegate uint tNtProtectVirtualMemory(IntPtr ProcesssHandle, ref IntPtr BaseAddress, ref UIntPtr RegionSize, MemoryProtection Protect, out MemoryProtection OldProtect); + [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] + private delegate uint tNtAllocateVirtualMemory(IntPtr ProcessHandle, ref IntPtr BaseAddress, IntPtr ZeroBits, ref UIntPtr RegionSize, AllocationType AllocationType, MemoryProtection Protect); + [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] + private delegate uint tNtFreeVirtualMemory(IntPtr ProcessHandle, ref IntPtr BaseAddress, ref UIntPtr RegionSize, FreeType FreeType); + [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] + private delegate uint tNtUnmapViewOfSection(IntPtr ProcessHandle, IntPtr BaseAddress); + [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] + private delegate IntPtr tMapViewOfFile(IntPtr hFileMappingObject, MapAccess dwDesiredAccess, int dwFileOffsetHigh, int dwFileOffsetLow, IntPtr dwNumBytesToMap); + + [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] + private delegate uint tNtRaiseHardError(uint ErrorStatus, uint NumberOfParameters, uint UnicodeStringParameterMask, IntPtr[] Parameters, uint ValidResponseOptions, out HardErrorResponse Response); + [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] + private delegate uint tNtOpenFile(out IntPtr FileHandle, uint DesiredAccess, ref OBJECT_ATTRIBUTES ObjectAttributes, out IO_STATUS_BLOCK IoStatusBlock, uint ShareAccess, uint OpenOptions); + [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] + private delegate uint tNtCreateSection(out IntPtr SectionHandle, uint DesiredAccess, ref OBJECT_ATTRIBUTES ObjectAttributes, ref LARGE_INTEGER MaximumSize, MemoryProtection SectionPageProtection, uint AllocationAttributes, IntPtr FileHandle); + + + private static IntPtr _ntdll; + private static tNtQueryInformationProcess _nt_query_information_process; + private static tNtSetInformationThread _nt_set_information_thread; + private static tNtClose _nt_close; + private static tNtProtectVirtualMemory _nt_protect_virtual_memory; + private static tNtAllocateVirtualMemory _nt_allocate_virtual_memory; + private static tNtFreeVirtualMemory _nt_free_virtual_memory; + private static tNtUnmapViewOfSection _nt_unmap_view_of_section; + private static tNtRaiseHardError _nt_raise_hard_error; + private static tNtOpenFile _nt_open_file; + private static tNtCreateSection _nt_create_section; + private static IntPtr _kernel32; + private static tEnumSystemFirmwareTables _enum_system_firmware_tables; + private static tGetSystemFirmwareTable _get_system_firmware_table; + private static tMapViewOfFile _map_view_of_file; + + + static Win32() + { + _ntdll = GetModuleHandleEnc((uint)Faces.NTDLL_NAME); + _nt_query_information_process = (tNtQueryInformationProcess)Marshal.GetDelegateForFunctionPointer(GetProcAddressEnc(_ntdll, (uint)Faces.NT_QUERY_INFORMATION_PROCESS_NAME), typeof(tNtQueryInformationProcess)); + _nt_set_information_thread = (tNtSetInformationThread)Marshal.GetDelegateForFunctionPointer(GetProcAddressEnc(_ntdll, (uint)Faces.NT_SET_INFORMATION_THREAD_NAME), typeof(tNtSetInformationThread)); + _nt_close = (tNtClose)Marshal.GetDelegateForFunctionPointer(GetProcAddressEnc(_ntdll, (uint)Faces.NT_CLOSE), typeof(tNtClose)); + _nt_protect_virtual_memory = (tNtProtectVirtualMemory)Marshal.GetDelegateForFunctionPointer(GetProcAddressEnc(_ntdll, (uint)Faces.NT_VIRTUAL_PROTECT_NAME), typeof(tNtProtectVirtualMemory)); + _nt_allocate_virtual_memory = (tNtAllocateVirtualMemory)Marshal.GetDelegateForFunctionPointer(GetProcAddressEnc(_ntdll, (uint)Faces.NT_ALLOCATE_VIRTUAL_MEMORY_NAME), typeof(tNtAllocateVirtualMemory)); + _nt_free_virtual_memory = (tNtFreeVirtualMemory)Marshal.GetDelegateForFunctionPointer(GetProcAddressEnc(_ntdll, (uint)Faces.NT_FREE_VIRTUAL_MEMORY_NAME), typeof(tNtFreeVirtualMemory)); + _nt_unmap_view_of_section = (tNtUnmapViewOfSection)Marshal.GetDelegateForFunctionPointer(GetProcAddressEnc(_ntdll, (uint)Faces.NT_UNMAP_VIEW_OF_SECTION), typeof(tNtUnmapViewOfSection)); + _nt_raise_hard_error = (tNtRaiseHardError)Marshal.GetDelegateForFunctionPointer(GetProcAddressEnc(_ntdll, (uint)Faces.NT_RAISE_HARD_ERROR_NAME), typeof(tNtRaiseHardError)); + _nt_open_file = (tNtOpenFile)Marshal.GetDelegateForFunctionPointer(GetProcAddressEnc(_ntdll, (uint)Faces.NT_OPEN_FILE_NAME), typeof(tNtOpenFile)); + _nt_create_section = (tNtCreateSection)Marshal.GetDelegateForFunctionPointer(GetProcAddressEnc(_ntdll, (uint)Faces.NT_CREATE_SECTION_NAME), typeof(tNtCreateSection)); + + _kernel32 = GetModuleHandleEnc((uint)Faces.KERNEL32_NAME); + IntPtr proc = GetProcAddressEnc(_kernel32, (uint)Faces.ENUM_SYSTEM_FIRMWARE_NAME); + if (proc != IntPtr.Zero) + _enum_system_firmware_tables = (tEnumSystemFirmwareTables)Marshal.GetDelegateForFunctionPointer(proc, typeof(tEnumSystemFirmwareTables)); + proc = GetProcAddressEnc(_kernel32, (uint)Faces.GET_SYSTEM_FIRMWARE_NAME); + if (proc != IntPtr.Zero) + _get_system_firmware_table = (tGetSystemFirmwareTable)Marshal.GetDelegateForFunctionPointer(proc, typeof(tGetSystemFirmwareTable)); + _map_view_of_file = (tMapViewOfFile)Marshal.GetDelegateForFunctionPointer(GetProcAddressEnc(_kernel32, (uint)Faces.NT_MAP_VIEW_OF_SECTION), typeof(tMapViewOfFile)); + } + + internal static IntPtr GetModuleHandleEnc(uint position) + { + long instance = Marshal.GetHINSTANCE(typeof(Loader).Module).ToInt64(); + var buffer = new byte[100]; + for (var pos = 0; pos < buffer.Length; pos++) + { + var c = (byte)(Marshal.ReadByte(new IntPtr(instance + position + pos)) ^ (BitRotate.Left((uint)Faces.STRING_DECRYPT_KEY, pos) + pos)); + if (c == 0) + { + if (pos > 0) + return Win32.GetModuleHandle(Encoding.ASCII.GetString(buffer, 0, pos)); + break; + } + + buffer[pos] = c; + } + + return IntPtr.Zero; + } + + [DllImport("kernel32", SetLastError = true)] + public static extern uint GetFileSize(IntPtr handle, IntPtr lpFileSizeHigh); + + [DllImport("kernel32", SetLastError = true)] + public static extern bool GetVolumeInformation( + string pathName, + StringBuilder volumeNameBuffer, + uint volumeNameSize, + ref uint volumeSerialNumber, + ref uint maximumComponentLength, + ref uint fileSystemFlags, + StringBuilder fileSystemNameBuffer, + uint fileSystemNameSize); + + [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)] + public static extern IntPtr GetModuleHandle(String lpModuleName); + + [StructLayout(LayoutKind.Sequential)] + public struct PROCESS_BASIC_INFORMATION + { + public IntPtr Reserved1; + public IntPtr PebBaseAddress; + public IntPtr Reserved2_0; + public IntPtr Reserved2_1; + public IntPtr UniqueProcessId; + public IntPtr InheritedFromUniqueProcessId; + } + + public enum PROCESSINFOCLASS + { + ProcessBasicInformation = 0x00, + ProcessDebugPort = 0x07, + ProcessDebugObjectHandle = 0x1e + } + + public enum THREADINFOCLASS + { + ThreadHideFromDebugger = 0x11 + } + + internal static IntPtr GetProcAddress(IntPtr module, object proc_name) + { + if (module == IntPtr.Zero || proc_name == null) + return IntPtr.Zero; + + unsafe + { + byte* ptr = (byte*)module.ToPointer(); + + PE.IMAGE_DOS_HEADER* dos_header = (PE.IMAGE_DOS_HEADER*)ptr; + if (dos_header->e_magic != PE.IMAGE_DOS_SIGNATURE) + return IntPtr.Zero; + + PE.IMAGE_NT_HEADERS* pe_header = (PE.IMAGE_NT_HEADERS*)(ptr + dos_header->e_lfanew); + if (pe_header->Signature != PE.IMAGE_NT_SIGNATURE) + return IntPtr.Zero; + + if (pe_header->FileHeader.SizeOfOptionalHeader == 0) + return IntPtr.Zero; + + PE.IMAGE_DATA_DIRECTORY* export_table; + byte* optional_header = (byte*)pe_header + Marshal.SizeOf(typeof(PE.IMAGE_NT_HEADERS)); + switch (*(UInt16*)(optional_header)) + { + case PE.IMAGE_NT_OPTIONAL_HDR32_MAGIC: + export_table = &((PE.IMAGE_OPTIONAL_HEADER32*)(optional_header))->ExportTable; + break; + case PE.IMAGE_NT_OPTIONAL_HDR64_MAGIC: + export_table = &((PE.IMAGE_OPTIONAL_HEADER64*)(optional_header))->ExportTable; + break; + default: + return IntPtr.Zero; + } + + if (export_table->VirtualAddress == 0) + return IntPtr.Zero; + + uint address = 0; + PE.IMAGE_EXPORT_DIRECTORY* export_directory = (PE.IMAGE_EXPORT_DIRECTORY*)(ptr + export_table->VirtualAddress); + if (proc_name is string) + { + string name = (string)proc_name; + if (export_directory->NumberOfNames > 0) + { + int left_index = 0; + int right_index = (int)export_directory->NumberOfNames - 1; + uint* names = (UInt32*)(ptr + export_directory->AddressOfNames); + while (left_index <= right_index) + { + int cur_index = (left_index + right_index) >> 1; + int cmp = String.CompareOrdinal(name, Marshal.PtrToStringAnsi(new IntPtr(module.ToInt64() + names[cur_index]))); + if (cmp < 0) + right_index = cur_index - 1; + else if (cmp > 0) + left_index = cur_index + 1; + else + { + uint ordinal_index = ((UInt16*)(ptr + export_directory->AddressOfNameOrdinals))[cur_index]; + if (ordinal_index < export_directory->NumberOfFunctions) + address = ((UInt32*)(ptr + export_directory->AddressOfFunctions))[ordinal_index]; + break; + } + } + } + } + else + { + uint ordinal_index = System.Convert.ToUInt32(proc_name) - export_directory->Base; + if (ordinal_index < export_directory->NumberOfFunctions) + address = ((UInt32*)(ptr + export_directory->AddressOfFunctions))[ordinal_index]; + } + + if (address == 0) + return IntPtr.Zero; + + if (address < export_table->VirtualAddress || address >= export_table->VirtualAddress + export_table->Size) + return new IntPtr(module.ToInt64() + address); + + string forwarded_name = Marshal.PtrToStringAnsi(new IntPtr(module.ToInt64() + address)); + int dot_pos = forwarded_name.IndexOf('.'); + if (dot_pos > 0) + { + IntPtr forwarded_module = Win32.GetModuleHandle(forwarded_name.Substring(0, dot_pos)); + if (forwarded_name[dot_pos + 1] == '#') + { + uint ordinal; + if (UInt32.TryParse(forwarded_name.Substring(dot_pos + 2), out ordinal)) + return GetProcAddress(forwarded_module, ordinal); + } + else + return GetProcAddress(forwarded_module, forwarded_name.Substring(dot_pos + 1)); + } + } + + return IntPtr.Zero; + } + + internal static IntPtr GetProcAddressEnc(IntPtr module, uint position) + { + long instance = Marshal.GetHINSTANCE(typeof(Loader).Module).ToInt64(); + var buffer = new byte[100]; + for (var pos = 0; pos < buffer.Length; pos++) + { + var c = (byte)(Marshal.ReadByte(new IntPtr(instance + position + pos)) ^ (BitRotate.Left((uint)Faces.STRING_DECRYPT_KEY, pos) + pos)); + if (c == 0) + { + if (pos > 0) + return GetProcAddress(module, Encoding.ASCII.GetString(buffer, 0, pos)); + break; + } + + buffer[pos] = c; + } + + return IntPtr.Zero; + } + + public static uint NtQueryInformationProcess(IntPtr processHandle, Win32.PROCESSINFOCLASS processInformationClass, + out object processInformation, int processInformationLength, out uint returnLength) + { + IntPtr mem = Marshal.AllocHGlobal(processInformationLength); + uint res = _nt_query_information_process(processHandle, processInformationClass, mem, processInformationLength, out returnLength); + if (res == 0) + { + Type type; + switch (processInformationClass) + { + case Win32.PROCESSINFOCLASS.ProcessBasicInformation: + type = typeof(Win32.PROCESS_BASIC_INFORMATION); + break; + case Win32.PROCESSINFOCLASS.ProcessDebugPort: + case Win32.PROCESSINFOCLASS.ProcessDebugObjectHandle: + type = typeof(IntPtr); + break; + default: + type = null; + break; + } + processInformation = Marshal.PtrToStructure(mem, type); + } + else + processInformation = null; + + Marshal.FreeHGlobal(mem); + return res; + } + + public static uint NtSetInformationThread(IntPtr ThreadHandle, Win32.THREADINFOCLASS ThreadInformationClass, IntPtr ThreadInformation, uint ThreadInformationLength) + { + return _nt_set_information_thread(ThreadHandle, ThreadInformationClass, ThreadInformation, ThreadInformationLength); + } + + public static uint EnumSystemFirmwareTables(uint firmwareTableProviderSignature, IntPtr firmwareTableBuffer, uint bufferSize) + { + return _enum_system_firmware_tables(firmwareTableProviderSignature, firmwareTableBuffer, bufferSize); + } + + public static uint GetSystemFirmwareTable(uint firmwareTableProviderSignature, uint firmwareTableID, IntPtr firmwareTableBuffer, uint bufferSize) + { + return _get_system_firmware_table(firmwareTableProviderSignature, firmwareTableID, firmwareTableBuffer, bufferSize); + } + + public static bool CloseHandle(IntPtr handle) + { + return (_nt_close(handle) == 0); + } + + public static IntPtr OpenFile(String FileName, uint DesiredAccess, uint ShareMode) + { + char[] preffix; + if (FileName[0] == '\\' && FileName[1] == '\\') + { + preffix = new char[7]; + + preffix[0] = '\\'; + preffix[1] = '?'; + preffix[2] = '?'; + preffix[3] = '\\'; + preffix[4] = 'U'; + preffix[5] = 'N'; + preffix[6] = 'C'; + } + else + { + preffix = new char[4]; + + preffix[0] = '\\'; + preffix[1] = '?'; + preffix[2] = '?'; + preffix[3] = '\\'; + } + + var str = new UNICODE_STRING(new string(preffix) + FileName); + var objectAttributes = new OBJECT_ATTRIBUTES(str, 0); + try + { + IntPtr res; + IO_STATUS_BLOCK io_status_block; + if (_nt_open_file(out res, DesiredAccess | (uint)Values.SYNCHRONIZE | (uint)Values.FILE_READ_ATTRIBUTES, ref objectAttributes, out io_status_block, ShareMode, (uint)Values.FILE_SYNCHRONOUS_IO_NONALERT | (uint)Values.FILE_NON_DIRECTORY_FILE) == 0) + return res; + } + finally + { + str.Dispose(); + objectAttributes.Dispose(); + } + + return InvalidHandleValue; + } + + public static bool VirtualProtect(IntPtr BaseAddress, UIntPtr RegionSize, MemoryProtection Protect, out MemoryProtection OldProtect) + { + return (_nt_protect_virtual_memory(CurrentProcess, ref BaseAddress, ref RegionSize, Protect, out OldProtect) == 0); + } + + public static IntPtr VirtualAlloc(IntPtr BaseAddress, UIntPtr RegionSize, AllocationType AllocationType, MemoryProtection Protect) + { + if (_nt_allocate_virtual_memory(CurrentProcess, ref BaseAddress, IntPtr.Zero, ref RegionSize, AllocationType, Protect) == 0) + return BaseAddress; + return IntPtr.Zero; + } + + public static bool VirtualFree(IntPtr BaseAddress, UIntPtr RegionSize, FreeType FreeType) + { + return (_nt_free_virtual_memory(CurrentProcess, ref BaseAddress, ref RegionSize, FreeType) == 0); + } + + public static IntPtr CreateFileMapping(IntPtr FileHandle, IntPtr Attributes, MemoryProtection Protect, uint MaximumSizeLow, uint MaximumSizeHigh, String Name) + { + uint desiredAccess = (uint)Values.SECTION_MAP_READ; + if (Protect == MemoryProtection.ReadWrite) + desiredAccess |= (uint)Values.SECTION_MAP_WRITE; + else if (Protect == MemoryProtection.ExecuteReadWrite) + desiredAccess |= (uint)Values.SECTION_MAP_WRITE | (uint)Values.SECTION_MAP_EXECUTE; + else if (Protect == MemoryProtection.ExecuteRead) + desiredAccess |= (uint)Values.SECTION_MAP_EXECUTE; + + IntPtr res; + var str = new UNICODE_STRING(null); + var objectAttributes = new OBJECT_ATTRIBUTES(str, 0); + try + { + var size = new LARGE_INTEGER(); + size.LowPart = MaximumSizeLow; + size.HighPart = MaximumSizeHigh; + if (_nt_create_section(out res, desiredAccess, ref objectAttributes, ref size, Protect, (uint)Values.SEC_COMMIT, FileHandle) == 0) + return res; + } + finally + { + str.Dispose(); + objectAttributes.Dispose(); + } + + return NullHandle; + } + + public static IntPtr MapViewOfFile(IntPtr hFileMappingObject, MapAccess dwDesiredAccess, int dwFileOffsetHigh, int dwFileOffsetLow, IntPtr dwNumBytesToMap) + { + return _map_view_of_file(hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, dwNumBytesToMap); + } + + public static bool UnmapViewOfFile(IntPtr BaseAddress) + { + return (_nt_unmap_view_of_section(CurrentProcess, BaseAddress) == 0); + } + + public static bool IsDebuggerPresent() + { + object obj; + if (NtQueryInformationProcess(CurrentProcess, PROCESSINFOCLASS.ProcessBasicInformation, out obj, Marshal.SizeOf(typeof(PROCESS_BASIC_INFORMATION)), out _) == 0) + { + if (Marshal.ReadByte(new IntPtr(((PROCESS_BASIC_INFORMATION)obj).PebBaseAddress.ToInt64() + 2)) != 0) // PEB.BeingDebugged + return true; + } + return false; + } + + public static bool CheckRemoteDebuggerPresent() + { + object obj; + if (NtQueryInformationProcess(CurrentProcess, PROCESSINFOCLASS.ProcessDebugPort, out obj, IntPtr.Size, out _) == 0) + { + if ((IntPtr)obj != IntPtr.Zero) + return true; + } + + if (NtQueryInformationProcess(CurrentProcess, PROCESSINFOCLASS.ProcessDebugObjectHandle, out _, IntPtr.Size, out _) == 0) + return true; + + return false; + } + + public static void ShowMessage(string Text, string Caption, MessageBoxButtons Buttons, MessageBoxIcon Icon) + { + IntPtr[] p = new IntPtr[4]; + var strText = new UNICODE_STRING(Text); + var strCaption = new UNICODE_STRING(Caption); + p[0] = Marshal.AllocHGlobal(Marshal.SizeOf(strText)); + p[1] = Marshal.AllocHGlobal(Marshal.SizeOf(strCaption)); + try + { + Marshal.StructureToPtr(strText, p[0], false); + Marshal.StructureToPtr(strCaption, p[1], false); + p[2] = new IntPtr((uint)Buttons | (uint)Icon); + p[3] = new IntPtr(-1); + + _nt_raise_hard_error(0x40000018 | 0x10000000, 4, 3, p, 0, out _); + } + finally + { + strText.Dispose(); + strCaption.Dispose(); + Marshal.FreeHGlobal(p[0]); + Marshal.FreeHGlobal(p[1]); + } + } + } + + internal class PE + { + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct IMAGE_DOS_HEADER + { + public UInt16 e_magic; + public UInt16 e_cblp; + public UInt16 e_cp; + public UInt16 e_crlc; + public UInt16 e_cparhdr; + public UInt16 e_minalloc; + public UInt16 e_maxalloc; + public UInt16 e_ss; + public UInt16 e_sp; + public UInt16 e_csum; + public UInt16 e_ip; + public UInt16 e_cs; + public UInt16 e_lfarlc; + public UInt16 e_ovno; + public UInt16 e_res_0; + public UInt16 e_res_1; + public UInt16 e_res_2; + public UInt16 e_res_3; + public UInt16 e_oemid; + public UInt16 e_oeminfo; + public UInt16 e_res2_0; + public UInt16 e_res2_1; + public UInt16 e_res2_2; + public UInt16 e_res2_3; + public UInt16 e_res2_4; + public UInt16 e_res2_5; + public UInt16 e_res2_6; + public UInt16 e_res2_7; + public UInt16 e_res2_8; + public UInt16 e_res2_9; + public UInt32 e_lfanew; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct IMAGE_FILE_HEADER + { + public UInt16 Machine; + public UInt16 NumberOfSections; + public UInt32 TimeDateStamp; + public UInt32 PointerToSymbolTable; + public UInt32 NumberOfSymbols; + public UInt16 SizeOfOptionalHeader; + public UInt16 Characteristics; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct IMAGE_NT_HEADERS + { + public UInt32 Signature; + public IMAGE_FILE_HEADER FileHeader; + //IMAGE_OPTIONAL_HEADER OptionalHeader; + } + + public const UInt16 IMAGE_DOS_SIGNATURE = 0x5A4D; + public const UInt32 IMAGE_NT_SIGNATURE = 0x00004550; + public const UInt16 IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b; + public const UInt16 IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b; + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct IMAGE_DATA_DIRECTORY + { + public UInt32 VirtualAddress; + public UInt32 Size; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct IMAGE_OPTIONAL_HEADER32 + { + public UInt16 Magic; + public Byte MajorLinkerVersion; + public Byte MinorLinkerVersion; + public UInt32 SizeOfCode; + public UInt32 SizeOfInitializedData; + public UInt32 SizeOfUninitializedData; + public UInt32 AddressOfEntryPoint; + public UInt32 BaseOfCode; + public UInt32 BaseOfData; + public UInt32 ImageBase; + public UInt32 SectionAlignment; + public UInt32 FileAlignment; + public UInt16 MajorOperatingSystemVersion; + public UInt16 MinorOperatingSystemVersion; + public UInt16 MajorImageVersion; + public UInt16 MinorImageVersion; + public UInt16 MajorSubsystemVersion; + public UInt16 MinorSubsystemVersion; + public UInt32 Win32VersionValue; + public UInt32 SizeOfImage; + public UInt32 SizeOfHeaders; + public UInt32 CheckSum; + public UInt16 Subsystem; + public UInt16 DllCharacteristics; + public UInt32 SizeOfStackReserve; + public UInt32 SizeOfStackCommit; + public UInt32 SizeOfHeapReserve; + public UInt32 SizeOfHeapCommit; + public UInt32 LoaderFlags; + public UInt32 NumberOfRvaAndSizes; + + public IMAGE_DATA_DIRECTORY ExportTable; + public IMAGE_DATA_DIRECTORY ImportTable; + public IMAGE_DATA_DIRECTORY ResourceTable; + public IMAGE_DATA_DIRECTORY ExceptionTable; + public IMAGE_DATA_DIRECTORY CertificateTable; + public IMAGE_DATA_DIRECTORY BaseRelocationTable; + public IMAGE_DATA_DIRECTORY Debug; + public IMAGE_DATA_DIRECTORY Architecture; + public IMAGE_DATA_DIRECTORY GlobalPtr; + public IMAGE_DATA_DIRECTORY TLSTable; + public IMAGE_DATA_DIRECTORY LoadConfigTable; + public IMAGE_DATA_DIRECTORY BoundImport; + public IMAGE_DATA_DIRECTORY IAT; + public IMAGE_DATA_DIRECTORY DelayImportDescriptor; + public IMAGE_DATA_DIRECTORY CLRRuntimeHeader; + public IMAGE_DATA_DIRECTORY Reserved; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct IMAGE_OPTIONAL_HEADER64 + { + public UInt16 Magic; + public Byte MajorLinkerVersion; + public Byte MinorLinkerVersion; + public UInt32 SizeOfCode; + public UInt32 SizeOfInitializedData; + public UInt32 SizeOfUninitializedData; + public UInt32 AddressOfEntryPoint; + public UInt32 BaseOfCode; + public UInt64 ImageBase; + public UInt32 SectionAlignment; + public UInt32 FileAlignment; + public UInt16 MajorOperatingSystemVersion; + public UInt16 MinorOperatingSystemVersion; + public UInt16 MajorImageVersion; + public UInt16 MinorImageVersion; + public UInt16 MajorSubsystemVersion; + public UInt16 MinorSubsystemVersion; + public UInt32 Win32VersionValue; + public UInt32 SizeOfImage; + public UInt32 SizeOfHeaders; + public UInt32 CheckSum; + public UInt16 Subsystem; + public UInt16 DllCharacteristics; + public UInt64 SizeOfStackReserve; + public UInt64 SizeOfStackCommit; + public UInt64 SizeOfHeapReserve; + public UInt64 SizeOfHeapCommit; + public UInt32 LoaderFlags; + public UInt32 NumberOfRvaAndSizes; + + public IMAGE_DATA_DIRECTORY ExportTable; + public IMAGE_DATA_DIRECTORY ImportTable; + public IMAGE_DATA_DIRECTORY ResourceTable; + public IMAGE_DATA_DIRECTORY ExceptionTable; + public IMAGE_DATA_DIRECTORY CertificateTable; + public IMAGE_DATA_DIRECTORY BaseRelocationTable; + public IMAGE_DATA_DIRECTORY Debug; + public IMAGE_DATA_DIRECTORY Architecture; + public IMAGE_DATA_DIRECTORY GlobalPtr; + public IMAGE_DATA_DIRECTORY TLSTable; + public IMAGE_DATA_DIRECTORY LoadConfigTable; + public IMAGE_DATA_DIRECTORY BoundImport; + public IMAGE_DATA_DIRECTORY IAT; + public IMAGE_DATA_DIRECTORY DelayImportDescriptor; + public IMAGE_DATA_DIRECTORY CLRRuntimeHeader; + public IMAGE_DATA_DIRECTORY Reserved; + } + + [StructLayout(LayoutKind.Sequential)] + public struct IMAGE_EXPORT_DIRECTORY + { + public UInt32 Characteristics; + public UInt32 TimeDateStamp; + public UInt16 MajorVersion; + public UInt16 MinorVersion; + public UInt32 Name; + public UInt32 Base; + public UInt32 NumberOfFunctions; + public UInt32 NumberOfNames; + public UInt32 AddressOfFunctions; + public UInt32 AddressOfNames; + public UInt32 AddressOfNameOrdinals; + } + } +}
\ No newline at end of file diff --git a/runtime/common.h b/runtime/common.h new file mode 100644 index 0000000..89e87de --- /dev/null +++ b/runtime/common.h @@ -0,0 +1,291 @@ +#ifndef COMMON_H +#define COMMON_H + +#ifdef VMP_GNU +#define VMP_IMPORT +#else +#define VMP_IMPORT __declspec(dllimport) +#ifdef WIN_DRIVER +#ifdef _WIN64 + #pragma comment(lib, "../bin/64/Driver/VMProtectDDK64.lib") +#else + #pragma comment(lib, "../bin/32/Driver/VMProtectDDK32.lib") +#endif // _WIN64 +#else +#ifdef _WIN64 +#ifdef NDEBUG + #pragma comment(lib, "../bin/64/Release/VMProtectSDK64.lib") +#else + #pragma comment(lib, "../bin/64/Debug/VMProtectSDK64.lib") +#endif +#else +#ifdef NDEBUG + #pragma comment(lib, "../bin/32/Release/VMProtectSDK32.lib") +#else + #pragma comment(lib, "../bin/32/Debug/VMProtectSDK32.lib") +#endif +#endif // _WIN64 +#endif // WIN_DRIVER +#endif // VMP_GNU + +#include "../sdk/sdk.h" + +const size_t NOT_ID = (size_t)-1; + +enum { + MESSAGE_DEBUGGER_FOUND, + MESSAGE_VIRTUAL_MACHINE_FOUND, + MESSAGE_FILE_CORRUPTED, + MESSAGE_SERIAL_NUMBER_REQUIRED, + MESSAGE_HWID_MISMATCHED, + MESSAGE_COUNT +}; + +#ifdef VMP_GNU +#define VMP_STR(s) s +#else +#define VMP_STR(s) L##s +#endif + +#define MESSAGE_DEBUGGER_FOUND_STR VMP_STR("A debugger has been found running in your system.\nPlease, unload it from memory and restart your program.") +#define MESSAGE_VIRTUAL_MACHINE_FOUND_STR VMP_STR("Sorry, this application cannot run under a Virtual Machine.") +#define MESSAGE_FILE_CORRUPTED_STR VMP_STR("File corrupted! This program has been manipulated and maybe\nit's infected by a Virus or cracked. This file won't work anymore.") +#define MESSAGE_SERIAL_NUMBER_REQUIRED_STR VMP_STR("This code requires valid serial number to run.\nProgram will be terminated.") +#define MESSAGE_HWID_MISMATCHED_STR VMP_STR("This application cannot be executed on this computer.") +#define MESSAGE_UNREGISTERED_VERSION_STR VMP_STR("This application is protected with unregistered version of VMProtect and cannot be executed on this computer.") + +enum { + VAR_IS_PATCH_DETECTED, + VAR_IS_DEBUGGER_DETECTED, + VAR_LOADER_CRC_INFO, + VAR_LOADER_CRC_INFO_SIZE, + VAR_LOADER_CRC_INFO_HASH, + VAR_SESSION_KEY, + VAR_DRIVER_UNLOAD, + VAR_CRC_IMAGE_SIZE, + VAR_LOADER_STATUS, + VAR_SERVER_DATE, + VAR_OS_BUILD_NUMBER, + VAR_CPU_COUNT, + VAR_CPU_HASH, + VAR_COUNT = VAR_CPU_HASH + 32 +}; + +enum { + FACE_MASK = 0xFACE0000U, + + FACE_RC5_P, + FACE_RC5_Q, + + FACE_STRING_INFO, + FACE_RESOURCE_INFO, + FACE_STORAGE_INFO, + FACE_REGISTRY_INFO, + FACE_LICENSE_INFO, + FACE_LICENSE_INFO_SIZE, + FACE_KEY_INFO, + FACE_RUNTIME_ENTRY, + FACE_CRC_INFO_SALT, + FACE_CRC_TABLE_ENTRY, + FACE_CRC_TABLE_SIZE, + FACE_CRC_TABLE_HASH, + FACE_TRIAL_HWID, + FACE_TRIAL_HWID_SIZE, + FACE_CORE_OPTIONS, + FACE_IMAGE_BASE, + FACE_FILE_BASE, + + FACE_NTOSKRNL_NAME, + FACE_HAL_NAME, + FACE_USER32_NAME, + FACE_MESSAGE_BOX_NAME, + FACE_KERNEL32_NAME, + FACE_CREATE_FILE_NAME, + FACE_CLOSE_HANDLE_NAME, + FACE_INITIALIZATION_ERROR, + FACE_PROC_NOT_FOUND, + FACE_ORDINAL_NOT_FOUND, + FACE_STRING_DECRYPT_KEY, + FACE_DRIVER_FORMAT_VALUE, + FACE_FILE_CORRUPTED, + FACE_LOADER_OPTIONS, + FACE_LOADER_DATA, + FACE_DEBUGGER_FOUND, + FACE_NT_SET_INFORMATION_PROCESS_NAME, + FACE_NT_RAISE_HARD_ERROR_NAME, + FACE_IS_WOW64_PROCESS_NAME, + FACE_WINE_GET_VERSION_NAME, + FACE_MACOSX_FORMAT_VALUE, + FACE_GNU_PTRACE, + FACE_UNREGISTERED_VERSION, + FACE_WTSAPI32_NAME, + FACE_WTS_SEND_MESSAGE_NAME, + FACE_NTDLL_NAME, + FACE_NT_QUERY_INFORMATION_NAME, + FACE_NT_SET_INFORMATION_THREAD_NAME, + FACE_SICE_NAME, + FACE_SIWVID_NAME, + FACE_NTICE_NAME, + FACE_ICEEXT_NAME, + FACE_SYSER_NAME, + FACE_VIRTUAL_MACHINE_FOUND, + FACE_SBIEDLL_NAME, + FACE_QUERY_VIRTUAL_MEMORY_NAME, + FACE_ENUM_SYSTEM_FIRMWARE_NAME, + FACE_GET_SYSTEM_FIRMWARE_NAME, + FACE_NT_QUERY_INFORMATION_PROCESS_NAME, + FACE_NT_VIRTUAL_PROTECT_NAME, + FACE_NT_OPEN_FILE_NAME, + FACE_NT_CREATE_SECTION_NAME, + FACE_NT_OPEN_SECTION_NAME, + FACE_NT_MAP_VIEW_OF_SECTION, + FACE_NT_UNMAP_VIEW_OF_SECTION, + FACE_NT_CLOSE, + FACE_SYSCALL, + FACE_NT_ALLOCATE_VIRTUAL_MEMORY_NAME, + FACE_NT_FREE_VIRTUAL_MEMORY_NAME, + + FACE_PACKER_INFO = 0xFACE0100U, + FACE_PACKER_INFO_SIZE, + FACE_FILE_CRC_INFO, + FACE_FILE_CRC_INFO_SIZE, + FACE_LOADER_CRC_INFO, + FACE_LOADER_CRC_INFO_SIZE, + FACE_SECTION_INFO, + FACE_SECTION_INFO_SIZE, + FACE_FIXUP_INFO, + FACE_FIXUP_INFO_SIZE, + FACE_RELOCATION_INFO, + FACE_RELOCATION_INFO_SIZE, + FACE_IAT_INFO, + FACE_IAT_INFO_SIZE, + FACE_IMPORT_INFO, + FACE_IMPORT_INFO_SIZE, + FACE_INTERNAL_IMPORT_INFO, + FACE_INTERNAL_IMPORT_INFO_SIZE, + FACE_MEMORY_CRC_INFO, + FACE_MEMORY_CRC_INFO_SIZE, + FACE_DELAY_IMPORT_INFO, + FACE_DELAY_IMPORT_INFO_SIZE, + FACE_LOADER_CRC_INFO_HASH, + FACE_MEMORY_CRC_INFO_HASH, + FACE_TLS_INDEX_INFO, + FACE_GNU_RELRO_INFO, + FACE_NON_PAGED_POOL_NX, + FACE_DEFAULT_MDL_PRIORITY, + + FACE_VAR = 0xFACE0200U, + FACE_VAR_IS_PATCH_DETECTED = FACE_VAR | (VAR_IS_PATCH_DETECTED << 4), + FACE_VAR_IS_DEBUGGER_DETECTED = FACE_VAR | (VAR_IS_DEBUGGER_DETECTED << 4), + FACE_VAR_LOADER_CRC_INFO = FACE_VAR | (VAR_LOADER_CRC_INFO << 4), + FACE_VAR_LOADER_CRC_INFO_SIZE = FACE_VAR | (VAR_LOADER_CRC_INFO_SIZE << 4), + FACE_VAR_LOADER_CRC_INFO_HASH = FACE_VAR | (VAR_LOADER_CRC_INFO_HASH << 4), + FACE_VAR_SESSION_KEY = FACE_VAR | (VAR_SESSION_KEY << 4), + FACE_VAR_DRIVER_UNLOAD = FACE_VAR | (VAR_DRIVER_UNLOAD << 4), + FACE_VAR_CRC_IMAGE_SIZE = FACE_VAR | (VAR_CRC_IMAGE_SIZE << 4), + FACE_VAR_LOADER_STATUS = FACE_VAR | (VAR_LOADER_STATUS << 4), + FACE_VAR_SERVER_DATE = FACE_VAR | (VAR_SERVER_DATE << 4), + FACE_VAR_CPU_COUNT = FACE_VAR | (VAR_CPU_COUNT << 4), + FACE_VAR_CPU_HASH = FACE_VAR | (VAR_CPU_HASH << 4), + FACE_VAR_OS_BUILD_NUMBER = FACE_VAR | (VAR_OS_BUILD_NUMBER << 4), + + FACE_VAR_SALT = 0xFACE0300U, + FACE_VAR_IS_PATCH_DETECTED_SALT = FACE_VAR_SALT | VAR_IS_PATCH_DETECTED, + FACE_VAR_IS_DEBUGGER_DETECTED_SALT = FACE_VAR_SALT | VAR_IS_DEBUGGER_DETECTED, + FACE_VAR_LOADER_CRC_INFO_SALT = FACE_VAR_SALT | VAR_LOADER_CRC_INFO, + FACE_VAR_LOADER_CRC_INFO_SIZE_SALT = FACE_VAR_SALT | VAR_LOADER_CRC_INFO_SIZE, + FACE_VAR_LOADER_CRC_INFO_HASH_SALT = FACE_VAR_SALT | VAR_LOADER_CRC_INFO_HASH, + FACE_VAR_DRIVER_UNLOAD_SALT = FACE_VAR_SALT | VAR_DRIVER_UNLOAD, + FACE_VAR_CRC_IMAGE_SIZE_SALT = FACE_VAR_SALT | VAR_CRC_IMAGE_SIZE, + FACE_VAR_SERVER_DATE_SALT = FACE_VAR_SALT | VAR_SERVER_DATE, + FACE_VAR_CPU_COUNT_SALT = FACE_VAR_SALT | VAR_CPU_COUNT, + FACE_VAR_CPU_HASH_SALT = FACE_VAR_SALT | VAR_CPU_HASH, + FACE_VAR_OS_BUILD_NUMBER_SALT = FACE_VAR_SALT | VAR_OS_BUILD_NUMBER, +}; + +enum { + LOADER_OPTION_CHECK_PATCH = 0x1, + LOADER_OPTION_CHECK_DEBUGGER = 0x2, + LOADER_OPTION_CHECK_KERNEL_DEBUGGER = 0x4, + LOADER_OPTION_EXIT_PROCESS = 0x8, + LOADER_OPTION_CHECK_VIRTUAL_MACHINE = 0x10 +}; + +enum { + CORE_OPTION_MEMORY_PROTECTION = 0x1, + CORE_OPTION_CHECK_DEBUGGER = 0x2 +}; + +enum { + FILE_LOAD = 0x1, + FILE_REGISTER = 0x2, + FILE_INSTALL = 0x4, +}; + +enum { + FIELD_BUILD_DATE, + FIELD_PUBLIC_EXP_OFFSET, + FIELD_PUBLIC_EXP_SIZE, + FIELD_MODULUS_OFFSET, + FIELD_MODULUS_SIZE, + FIELD_BLACKLIST_OFFSET, + FIELD_BLACKLIST_SIZE, + FIELD_ACTIVATION_URL_OFFSET, + FIELD_ACTIVATION_URL_SIZE, + FIELD_CRC_OFFSET, + FIELD_COUNT +}; + +enum { + WOW64_FLAG = 0x8000 +}; + +#ifndef _CONSOLE // google test +#define FACE_TO_INDEX(i) ((uint32_t)(i)/sizeof(size_t)) +#ifdef VMP_GNU +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warray-bounds" +#endif +#else +#define FACE_TO_INDEX(i) (((uint32_t)(i) & 0xff) >> 4) +#endif + +struct GlobalData { + bool is_patch_detected() { return ((v_[FACE_TO_INDEX(FACE_VAR_IS_PATCH_DETECTED)] ^ FACE_VAR_IS_PATCH_DETECTED_SALT) != 0); } //-V557 + bool is_debugger_detected() { return ((v_[FACE_TO_INDEX(FACE_VAR_IS_DEBUGGER_DETECTED)] ^ FACE_VAR_IS_DEBUGGER_DETECTED_SALT) != 0); } //-V557 + size_t loader_crc_info() { return (v_[FACE_TO_INDEX(FACE_VAR_LOADER_CRC_INFO)] ^ FACE_VAR_LOADER_CRC_INFO_SALT); } //-V557 + size_t loader_crc_size() { return (v_[FACE_TO_INDEX(FACE_VAR_LOADER_CRC_INFO_SIZE)] ^ FACE_VAR_LOADER_CRC_INFO_SIZE_SALT); } //-V557 + size_t loader_crc_hash() { return (v_[FACE_TO_INDEX(FACE_VAR_LOADER_CRC_INFO_HASH)] ^ FACE_VAR_LOADER_CRC_INFO_HASH_SALT); } //-V557 + size_t cpu_hash(size_t index) { return (v_[FACE_TO_INDEX(FACE_VAR_CPU_HASH) + index] ^ FACE_VAR_CPU_HASH_SALT); } + size_t cpu_count() { return (v_[FACE_TO_INDEX(FACE_VAR_CPU_COUNT)] ^ FACE_VAR_CPU_COUNT_SALT); } //-V557 + size_t session_key() { return (v_[FACE_TO_INDEX(FACE_VAR_SESSION_KEY)]); } //-V557 + size_t driver_unload() { return (v_[FACE_TO_INDEX(FACE_VAR_DRIVER_UNLOAD)] ^ FACE_VAR_DRIVER_UNLOAD_SALT); } //-V557 + size_t crc_image_size() { return (v_[FACE_TO_INDEX(FACE_VAR_CRC_IMAGE_SIZE)] ^ FACE_VAR_CRC_IMAGE_SIZE_SALT); } //-V557 + uint32_t loader_status() { return static_cast<uint32_t>(v_[FACE_TO_INDEX(FACE_VAR_LOADER_STATUS)]); } //-V557 + uint32_t server_date() { return static_cast<uint32_t>(v_[FACE_TO_INDEX(FACE_VAR_SERVER_DATE)] ^ FACE_VAR_SERVER_DATE_SALT); } //-V557 + uint32_t os_build_number() { return static_cast<uint32_t>(v_[FACE_TO_INDEX(FACE_VAR_OS_BUILD_NUMBER)] ^ FACE_VAR_OS_BUILD_NUMBER_SALT); } //-V557 + + void set_is_patch_detected(bool value) { v_[FACE_TO_INDEX(FACE_VAR_IS_PATCH_DETECTED)] = static_cast<size_t>(value) ^ FACE_VAR_IS_PATCH_DETECTED_SALT; } //-V557 + void set_is_debugger_detected(bool value) { v_[FACE_TO_INDEX(FACE_VAR_IS_DEBUGGER_DETECTED)] = static_cast<size_t>(value) ^ FACE_VAR_IS_DEBUGGER_DETECTED_SALT; } //-V557 + void set_loader_crc_info(size_t value) { v_[FACE_TO_INDEX(FACE_VAR_LOADER_CRC_INFO)] = value ^ FACE_VAR_LOADER_CRC_INFO_SALT; } //-V557 + void set_loader_crc_size(size_t value) { v_[FACE_TO_INDEX(FACE_VAR_LOADER_CRC_INFO_SIZE)] = value ^ FACE_VAR_LOADER_CRC_INFO_SIZE_SALT; } //-V557 + void set_loader_crc_hash(size_t value) { v_[FACE_TO_INDEX(FACE_VAR_LOADER_CRC_INFO_HASH)] = value ^ FACE_VAR_LOADER_CRC_INFO_HASH_SALT; } //-V557 + void set_cpu_hash(size_t index, size_t value) { v_[FACE_TO_INDEX(FACE_VAR_CPU_HASH) + index] = value ^ FACE_VAR_CPU_HASH_SALT; } + void set_cpu_count(size_t value) { v_[FACE_TO_INDEX(FACE_VAR_CPU_COUNT)] = value ^ FACE_VAR_CPU_COUNT_SALT; } //-V557 + void set_session_key(size_t value) { v_[FACE_TO_INDEX(FACE_VAR_SESSION_KEY)] = value; } //-V557 + void set_driver_unload(size_t value) { v_[FACE_TO_INDEX(FACE_VAR_DRIVER_UNLOAD)] = value ^ FACE_VAR_DRIVER_UNLOAD_SALT; } //-V557 + void set_crc_image_size(size_t value) { v_[FACE_TO_INDEX(FACE_VAR_CRC_IMAGE_SIZE)] = value ^ FACE_VAR_CRC_IMAGE_SIZE_SALT; } //-V557 + void set_loader_status(uint32_t value) { v_[FACE_TO_INDEX(FACE_VAR_LOADER_STATUS)] = value; } //-V557 + void set_server_date(uint32_t value) { v_[FACE_TO_INDEX(FACE_VAR_SERVER_DATE)] = value ^ FACE_VAR_SERVER_DATE_SALT; } //-V557 + void set_os_build_number(uint32_t value) { v_[FACE_TO_INDEX(FACE_VAR_OS_BUILD_NUMBER)] = value ^ FACE_VAR_OS_BUILD_NUMBER_SALT; } //-V557 +private: + size_t v_[VAR_COUNT]; +}; + +#ifndef _CONSOLE +#ifdef VMP_GNU +#pragma clang diagnostic pop +#endif +#endif + +#endif
\ No newline at end of file diff --git a/runtime/core.cc b/runtime/core.cc new file mode 100644 index 0000000..1344322 --- /dev/null +++ b/runtime/core.cc @@ -0,0 +1,1365 @@ +#include "common.h" +#include "utils.h" +#include "objects.h" + +#include "crypto.h" +#include "core.h" +#include "string_manager.h" +#include "licensing_manager.h" +#include "hwid.h" + +#ifdef VMP_GNU +#include "loader.h" +#elif defined(WIN_DRIVER) +#include "loader.h" +#else +#include "resource_manager.h" +#include "file_manager.h" +#include "registry_manager.h" +#include "hook_manager.h" +#endif + +GlobalData *loader_data = NULL; +#ifdef WIN_DRIVER +__declspec(noinline) void * ExAllocateNonPagedPoolNx(size_t size) +{ + return ExAllocatePool((POOL_TYPE)FACE_NON_PAGED_POOL_NX, size); +} + +void * __cdecl operator new(size_t size) +{ + if (size) + return ExAllocateNonPagedPoolNx(size); + + return NULL; +} + +void __cdecl operator delete(void* p) +{ + if (p) + ExFreePool(p); +} + +void __cdecl operator delete(void* p, size_t) +{ + if (p) + ExFreePool(p); +} + +void * __cdecl operator new[](size_t size) +{ + if (size) + return ExAllocateNonPagedPoolNx(size); + + return NULL; +} + +void __cdecl operator delete[](void *p) +{ + if (p) + ExFreePool(p); +} +#endif + +/** + * initialization functions + */ + +#ifdef VMP_GNU + +EXPORT_API bool WINAPI DllMain(HMODULE hModule, bool is_init) __asm__ ("DllMain"); +bool WINAPI DllMain(HMODULE hModule, bool is_init) +{ + if (is_init) { + if (!Core::Instance()->Init(hModule)) { + Core::Free(); + return false; + } + } else { + Core::Free(); + } + return true; +} + +#elif defined(WIN_DRIVER) + +NTSTATUS DllMain(HMODULE hModule, bool is_init) +{ + if (is_init) { + if (!Core::Instance()->Init(hModule)) { + Core::Free(); + return STATUS_ACCESS_DENIED; + } + } else { + Core::Free(); + } + return STATUS_SUCCESS; +} + +#else + +BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) +{ + switch (dwReason) { + case DLL_PROCESS_ATTACH: + if (!Core::Instance()->Init(hModule)) { + Core::Free(); + return FALSE; + } + break; + case DLL_PROCESS_DETACH: + Core::Free(); + break; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + } + return TRUE; +} +#endif + +/** + * exported functions + */ + +NOINLINE bool InternalFindFirmwareVendor(const uint8_t *data, size_t data_size) +{ + for (size_t i = 0; i < data_size; i++) { +#ifdef __unix__ + if (i + 3 < data_size && data[i + 0] == 'Q' && data[i + 1] == 'E' && data[i + 2] == 'M' && data[i + 3] == 'U') + return true; + if (i + 8 < data_size && 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_size && 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; +#else + if (i + 9 < data_size && 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; +#endif + if (i + 5 < data_size && 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_size && 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; +} + +#ifdef VMP_GNU +EXPORT_API bool WINAPI ExportedIsValidImageCRC() __asm__ ("ExportedIsValidImageCRC"); +EXPORT_API bool WINAPI ExportedIsDebuggerPresent(bool check_kernel_mode) __asm__ ("ExportedIsDebuggerPresent"); +EXPORT_API bool WINAPI ExportedIsVirtualMachinePresent() __asm__ ("ExportedIsVirtualMachinePresent"); +EXPORT_API bool WINAPI ExportedIsProtected() __asm__ ("ExportedIsProtected"); +#endif + +struct CRCData { + uint8_t *ImageBase; + uint32_t Table; + uint32_t Size; + uint32_t Hash; + NOINLINE CRCData() + { + ImageBase = reinterpret_cast<uint8_t *>(FACE_IMAGE_BASE); + Table = FACE_CRC_TABLE_ENTRY; + Size = FACE_CRC_TABLE_SIZE; + Hash = FACE_CRC_TABLE_HASH; + } +}; + +bool WINAPI ExportedIsValidImageCRC() +{ + if (loader_data->is_patch_detected()) + return false; + + const CRCData crc_data; + + bool res = true; + uint8_t *image_base = crc_data.ImageBase; + uint8_t *crc_table = image_base + crc_data.Table; + uint32_t crc_table_size = *reinterpret_cast<uint32_t *>(image_base + crc_data.Size); + uint32_t crc_table_hash = *reinterpret_cast<uint32_t *>(image_base + crc_data.Hash); + +#ifdef WIN_DRIVER + uint32_t image_size = 0; + if (loader_data->loader_status() == STATUS_SUCCESS) { + IMAGE_DOS_HEADER *dos_header = reinterpret_cast<IMAGE_DOS_HEADER *>(image_base); + if (dos_header->e_magic == IMAGE_DOS_SIGNATURE) { + IMAGE_NT_HEADERS *pe_header = reinterpret_cast<IMAGE_NT_HEADERS *>(image_base + dos_header->e_lfanew); + if (pe_header->Signature == IMAGE_NT_SIGNATURE) { + IMAGE_SECTION_HEADER *sections = reinterpret_cast<IMAGE_SECTION_HEADER *>(reinterpret_cast<uint8_t *>(pe_header) + offsetof(IMAGE_NT_HEADERS, OptionalHeader) + pe_header->FileHeader.SizeOfOptionalHeader); + for (size_t i = 0; i < pe_header->FileHeader.NumberOfSections; i++) { + IMAGE_SECTION_HEADER *section = sections + i; + if (section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) { + image_size = section->VirtualAddress; + break; + } + } + } + } + } +#endif + + // check memory CRC + { + if (crc_table_hash != CalcCRC(crc_table, crc_table_size)) + res = false; + CRCValueCryptor crc_cryptor; + for (size_t i = 0; i < crc_table_size; i += sizeof(CRC_INFO)) { + CRC_INFO crc_info = *reinterpret_cast<CRC_INFO *>(crc_table + i); + crc_info.Address = crc_cryptor.Decrypt(crc_info.Address); + crc_info.Size = crc_cryptor.Decrypt(crc_info.Size); + crc_info.Hash = crc_cryptor.Decrypt(crc_info.Hash); +#ifdef WIN_DRIVER + if (image_size && image_size < crc_info.Address + crc_info.Size) + continue; +#endif + + if (crc_info.Hash != CalcCRC(image_base + crc_info.Address, crc_info.Size)) + res = false; + } + } + + // check header and loader CRC + crc_table = image_base + loader_data->loader_crc_info(); + crc_table_size = static_cast<uint32_t>(loader_data->loader_crc_size()); + crc_table_hash = static_cast<uint32_t>(loader_data->loader_crc_hash()); + { + if (crc_table_hash != CalcCRC(crc_table, crc_table_size)) + res = false; + CRCValueCryptor crc_cryptor; + for (size_t i = 0; i < crc_table_size; i += sizeof(CRC_INFO)) { + CRC_INFO crc_info = *reinterpret_cast<CRC_INFO *>(crc_table + i); + crc_info.Address = crc_cryptor.Decrypt(crc_info.Address); + crc_info.Size = crc_cryptor.Decrypt(crc_info.Size); + crc_info.Hash = crc_cryptor.Decrypt(crc_info.Hash); +#ifdef WIN_DRIVER + if (image_size && image_size < crc_info.Address + crc_info.Size) + continue; +#endif + + if (crc_info.Hash != CalcCRC(image_base + crc_info.Address, crc_info.Size)) + res = false; + } + } + +#ifndef DEMO +#ifdef VMP_GNU +#elif defined(WIN_DRIVER) +#else + // check memory type of loader_data + HMODULE ntdll = GetModuleHandleA(VMProtectDecryptStringA("ntdll.dll")); + typedef NTSTATUS(NTAPI tNtQueryVirtualMemory)(HANDLE ProcessHandle, PVOID BaseAddress, MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID MemoryInformation, SIZE_T MemoryInformationLength, PSIZE_T ReturnLength); + tNtQueryVirtualMemory *query_virtual_memory = reinterpret_cast<tNtQueryVirtualMemory *>(InternalGetProcAddress(ntdll, VMProtectDecryptStringA("NtQueryVirtualMemory"))); + if (query_virtual_memory) { + MEMORY_BASIC_INFORMATION memory_info; + NTSTATUS status = query_virtual_memory(NtCurrentProcess(), loader_data, MemoryBasicInformation, &memory_info, sizeof(memory_info), NULL); + if (NT_SUCCESS(status) && memory_info.AllocationBase == image_base) + res = false; + } +#endif +#endif + + return res; +} + +bool WINAPI ExportedIsVirtualMachinePresent() +{ + // hardware detection + int cpu_info[4]; + __cpuid(cpu_info, 1); + if ((cpu_info[2] >> 31) & 1) { +#ifndef VMP_GNU + // check Hyper-V root partition + cpu_info[1] = 0; + cpu_info[2] = 0; + cpu_info[3] = 0; + __cpuid(cpu_info, 0x40000000); + if (cpu_info[1] == 0x7263694d && cpu_info[2] == 0x666f736f && cpu_info[3] == 0x76482074) { // "Microsoft Hv" + cpu_info[1] = 0; + __cpuid(cpu_info, 0x40000003); + if (cpu_info[1] & 1) + return false; + } +#endif + return true; + } + +#ifndef VMP_GNU + uint64_t val; + uint8_t mem_val; + __try { + // set T flag + __writeeflags(__readeflags() | 0x100); + val = __rdtsc(); + __nop(); + loader_data->set_is_debugger_detected(true); + } __except(mem_val = *static_cast<uint8_t *>((GetExceptionInformation())->ExceptionRecord->ExceptionAddress), EXCEPTION_EXECUTE_HANDLER) { + if (mem_val != 0x90) + return true; + } + + __try { + // set T flag + __writeeflags(__readeflags() | 0x100); + __cpuid(cpu_info, 1); + __nop(); + loader_data->set_is_debugger_detected(true); + } __except(mem_val = *static_cast<uint8_t *>((GetExceptionInformation())->ExceptionRecord->ExceptionAddress), EXCEPTION_EXECUTE_HANDLER) { + if (mem_val != 0x90) + return true; + } +#endif + + // software detection +#ifdef __APPLE__ + // FIXME +#elif defined(__unix__) + FILE *fsys_vendor = fopen(VMProtectDecryptStringA("/sys/devices/virtual/dmi/id/sys_vendor"), "r"); + if (fsys_vendor) { + char sys_vendor[256] = {0}; + fgets(sys_vendor, sizeof(sys_vendor), fsys_vendor); + fclose(fsys_vendor); + if (InternalFindFirmwareVendor(reinterpret_cast<uint8_t *>(sys_vendor), sizeof(sys_vendor))) + return true; + } +#elif defined(WIN_DRIVER) + // FIXME +#else + HMODULE dll = GetModuleHandleA(VMProtectDecryptStringA("kernel32.dll")); + bool is_found = false; + typedef UINT (WINAPI tEnumSystemFirmwareTables)(DWORD FirmwareTableProviderSignature, PVOID pFirmwareTableEnumBuffer, DWORD BufferSize); + typedef UINT (WINAPI tGetSystemFirmwareTable)(DWORD FirmwareTableProviderSignature, DWORD FirmwareTableID, PVOID pFirmwareTableBuffer, DWORD BufferSize); + tEnumSystemFirmwareTables *enum_system_firmware_tables = reinterpret_cast<tEnumSystemFirmwareTables *>(InternalGetProcAddress(dll, VMProtectDecryptStringA("EnumSystemFirmwareTables"))); + tGetSystemFirmwareTable *get_system_firmware_table = reinterpret_cast<tGetSystemFirmwareTable *>(InternalGetProcAddress(dll, VMProtectDecryptStringA("GetSystemFirmwareTable"))); + + if (enum_system_firmware_tables && get_system_firmware_table) { + UINT tables_size = enum_system_firmware_tables('FIRM', NULL, 0); + if (tables_size) { + DWORD *tables = new DWORD[tables_size / sizeof(DWORD)]; + enum_system_firmware_tables('FIRM', tables, tables_size); + for (size_t i = 0; i < tables_size / sizeof(DWORD); i++) { + UINT data_size = get_system_firmware_table('FIRM', tables[i], NULL, 0); + if (data_size) { + uint8_t *data = new uint8_t[data_size]; + get_system_firmware_table('FIRM', tables[i], data, data_size); + if (InternalFindFirmwareVendor(data, data_size)) + is_found = true; + delete [] data; + } + } + delete [] tables; + } + } else { + dll = LoadLibraryA(VMProtectDecryptStringA("ntdll.dll")); + typedef NTSTATUS (WINAPI tNtOpenSection)(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes); + typedef NTSTATUS (WINAPI tNtMapViewOfSection)(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, SECTION_INHERIT InheritDisposition, ULONG AllocationType, ULONG Win32Protect); + typedef NTSTATUS (WINAPI tNtUnmapViewOfSection)(HANDLE ProcessHandle, PVOID BaseAddress); + typedef NTSTATUS (WINAPI tNtClose)(HANDLE Handle); + + tNtOpenSection *open_section = reinterpret_cast<tNtOpenSection *>(InternalGetProcAddress(dll, VMProtectDecryptStringA("NtOpenSection"))); + tNtMapViewOfSection *map_view_of_section = reinterpret_cast<tNtMapViewOfSection *>(InternalGetProcAddress(dll, VMProtectDecryptStringA("NtMapViewOfSection"))); + tNtUnmapViewOfSection *unmap_view_of_section = reinterpret_cast<tNtUnmapViewOfSection *>(InternalGetProcAddress(dll, VMProtectDecryptStringA("NtUnmapViewOfSection"))); + tNtClose *close = reinterpret_cast<tNtClose *>(InternalGetProcAddress(dll, VMProtectDecryptStringA("NtClose"))); + + if (open_section && map_view_of_section && unmap_view_of_section && close) { + HANDLE process = NtCurrentProcess(); + HANDLE physical_memory = NULL; + UNICODE_STRING str; + OBJECT_ATTRIBUTES attrs; + + wchar_t buf[] = {'\\','d','e','v','i','c','e','\\','p','h','y','s','i','c','a','l','m','e','m','o','r','y',0}; + str.Buffer = buf; + str.Length = sizeof(buf) - sizeof(wchar_t); + str.MaximumLength = sizeof(buf); + + InitializeObjectAttributes(&attrs, &str, OBJ_CASE_INSENSITIVE, NULL, NULL); + NTSTATUS status = open_section(&physical_memory, SECTION_MAP_READ, &attrs); + if (NT_SUCCESS(status)) { + void *data = NULL; + SIZE_T data_size = 0x10000; + LARGE_INTEGER offset; + offset.QuadPart = 0xc0000; + + status = map_view_of_section(physical_memory, process, &data, NULL, data_size, &offset, &data_size, ViewShare, 0, PAGE_READONLY); + if (NT_SUCCESS(status)) { + if (InternalFindFirmwareVendor(static_cast<uint8_t *>(data), data_size)) + is_found = true; + unmap_view_of_section(process, data); + } + close(physical_memory); + } + } + } + if (is_found) + return true; + + if (GetModuleHandleA(VMProtectDecryptStringA("sbiedll.dll"))) + return true; +#endif + + return false; +} + +bool WINAPI ExportedIsDebuggerPresent(bool check_kernel_mode) +{ + if (loader_data->is_debugger_detected()) + return true; + +#if defined(__unix__) + FILE *file = fopen(VMProtectDecryptStringA("/proc/self/status"), "r"); + if (file) { + char data[100]; + int tracer_pid = 0; + while (fgets(data, sizeof(data), file)) { + if (data[0] == 'T' && data[1] == 'r' && data[2] == 'a' && data[3] == 'c' && data[4] == 'e' && data[5] == 'r' && data[6] == 'P' && data[7] == 'i' && data[8] == 'd' && data[9] == ':') { + char *tracer_ptr = data + 10; + // skip spaces + while (char c = *tracer_ptr) { + if (c == ' ' || c == '\t') { + tracer_ptr++; + continue; + } + else { + break; + } + } + // atoi + while (char c = *tracer_ptr++) { + if (c >= '0' && c <= '9') { + tracer_pid *= 10; + tracer_pid += c - '0'; + } + else { + if (c != '\n' && c != '\r') + tracer_pid = 0; + break; + } + } + break; + } + } + fclose(file); + + if (tracer_pid && tracer_pid != 1) + return true; + } +#elif defined(__APPLE__) + (void)check_kernel_mode; + + int junk; + int mib[4]; + kinfo_proc info; + size_t size; + + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + + info.kp_proc.p_flag = 0; + + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + // Call sysctl. + + size = sizeof(info); + junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0); + + // We're being debugged if the P_TRACED flag is set. + if ((info.kp_proc.p_flag & P_TRACED) != 0) + return true; +#else +#ifdef WIN_DRIVER +#else + HMODULE kernel32 = GetModuleHandleA(VMProtectDecryptStringA("kernel32.dll")); + HMODULE ntdll = GetModuleHandleA(VMProtectDecryptStringA("ntdll.dll")); + HANDLE process = NtCurrentProcess(); + size_t syscall = FACE_SYSCALL; + uint32_t sc_query_information_process = 0; + + if (ntdll) { +#ifndef DEMO + if (InternalGetProcAddress(ntdll, VMProtectDecryptStringA("wine_get_version")) == NULL) { +#ifndef _WIN64 + BOOL is_wow64 = FALSE; + typedef BOOL(WINAPI tIsWow64Process)(HANDLE Process, PBOOL Wow64Process); + tIsWow64Process *is_wow64_process = reinterpret_cast<tIsWow64Process *>(InternalGetProcAddress(kernel32, VMProtectDecryptStringA("IsWow64Process"))); + if (is_wow64_process) + is_wow64_process(process, &is_wow64); +#endif + + uint32_t os_build_number = loader_data->os_build_number(); + + if (os_build_number == WINDOWS_XP) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x009a; + } + else +#endif + { + sc_query_information_process = 0x0016; + } + } + else if (os_build_number == WINDOWS_2003) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x00a1; + } + else +#endif + { + sc_query_information_process = 0x0016; + } + } + else if (os_build_number == WINDOWS_VISTA) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x00e4; + } + else +#endif + { + sc_query_information_process = 0x0016; + } + } + else if (os_build_number == WINDOWS_VISTA_SP1) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x00e4; + } + else +#endif + { + sc_query_information_process = 0x0016; + } + + } + else if (os_build_number == WINDOWS_VISTA_SP2) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x00e4; + } + else +#endif + { + sc_query_information_process = 0x0016; + } + } + else if (os_build_number == WINDOWS_7) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x00ea; + } + else +#endif + { + sc_query_information_process = 0x0016; + } + } + else if (os_build_number == WINDOWS_7_SP1) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x00ea; + } + else +#endif + { + sc_query_information_process = 0x0016; + } + } + else if (os_build_number == WINDOWS_8) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x00b0; + } + else +#endif + { + sc_query_information_process = 0x0017; + } + } + else if (os_build_number == WINDOWS_8_1) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x00b3; + } + else +#endif + { + sc_query_information_process = 0x0018; + } + } + else if (os_build_number == WINDOWS_10_TH1) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x00b5; + } + else +#endif + { + sc_query_information_process = 0x0019; + } + } + else if (os_build_number == WINDOWS_10_TH2) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x00b5; + } + else +#endif + { + sc_query_information_process = 0x0019; + } + } + else if (os_build_number == WINDOWS_10_RS1) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x00b7; + } + else +#endif + { + sc_query_information_process = 0x0019; + } + } + else if (os_build_number == WINDOWS_10_RS2) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x00b8; + } + else +#endif + { + sc_query_information_process = 0x0019; + } + } + else if (os_build_number == WINDOWS_10_RS3) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x00b9; + } + else +#endif + { + sc_query_information_process = 0x0019; + } + } + else if (os_build_number == WINDOWS_10_RS4) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x00b9; + } + else +#endif + { + sc_query_information_process = 0x0019; + } + } + else if (os_build_number == WINDOWS_10_RS5) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x00b9; + } + else +#endif + { + sc_query_information_process = 0x0019; + } + } + else if (os_build_number == WINDOWS_10_19H1) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x00b9; + } + else +#endif + { + sc_query_information_process = 0x0019; + } + } + else if (os_build_number == WINDOWS_10_19H2) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x00b9; + } + else +#endif + { + sc_query_information_process = 0x0019; + } + } + else if (os_build_number == WINDOWS_10_20H1) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x00b9; + } + else +#endif + { + sc_query_information_process = 0x0019; + } + } + else if (os_build_number == WINDOWS_10_20H2) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x00b9; + } + else +#endif + { + sc_query_information_process = 0x0019; + } + } + else if (os_build_number == WINDOWS_10_21H1) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x00b9; + } + else +#endif + { + sc_query_information_process = 0x0019; + } + } + else if (os_build_number == WINDOWS_10_21H2) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x00b9; + } + else +#endif + { + sc_query_information_process = 0x0019; + } + } + else if (os_build_number == WINDOWS_10_22H2) { +#ifndef _WIN64 + if (!is_wow64) { + sc_query_information_process = 0x00b9; + } + else +#endif + { + sc_query_information_process = 0x0019; + } + } +#ifndef _WIN64 + if (is_wow64 && sc_query_information_process) { + sc_query_information_process |= WOW64_FLAG | (0x03 << 24); + } +#endif + } +#endif + } + +#ifdef _WIN64 + PEB64 *peb = reinterpret_cast<PEB64 *>(__readgsqword(0x60)); +#else + PEB32 *peb = reinterpret_cast<PEB32 *>(__readfsdword(0x30)); +#endif + if (peb->BeingDebugged) + return true; + + { + size_t drx; + uint64_t val; + CONTEXT *ctx; + __try { + __writeeflags(__readeflags() | 0x100); + val = __rdtsc(); + __nop(); + return true; + } + __except (ctx = (GetExceptionInformation())->ContextRecord, + drx = (ctx->ContextFlags & CONTEXT_DEBUG_REGISTERS) ? ctx->Dr0 | ctx->Dr1 | ctx->Dr2 | ctx->Dr3 : 0, + EXCEPTION_EXECUTE_HANDLER) { + if (drx) + return true; + } + } + + typedef NTSTATUS(NTAPI tNtQueryInformationProcess)(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength); + if (sc_query_information_process) { + HANDLE debug_object; + if (NT_SUCCESS(reinterpret_cast<tNtQueryInformationProcess *>(syscall | sc_query_information_process)(process, ProcessDebugPort, &debug_object, sizeof(debug_object), NULL)) && debug_object != 0) + return true; + debug_object = 0; + if (NT_SUCCESS(reinterpret_cast<tNtQueryInformationProcess *>(syscall | sc_query_information_process)(process, ProcessDebugObjectHandle, &debug_object, sizeof(debug_object), reinterpret_cast<PULONG>(&debug_object))) + || debug_object == 0) + return true; + } + else if (tNtQueryInformationProcess *query_information_process = reinterpret_cast<tNtQueryInformationProcess *>(InternalGetProcAddress(ntdll, VMProtectDecryptStringA("NtQueryInformationProcess")))) { + HANDLE debug_object; + if (NT_SUCCESS(query_information_process(process, ProcessDebugPort, &debug_object, sizeof(debug_object), NULL)) && debug_object != 0) + return true; + if (NT_SUCCESS(query_information_process(process, ProcessDebugObjectHandle, &debug_object, sizeof(debug_object), NULL))) + return true; + } + +#endif +#ifdef WIN_DRIVER + if (true) { +#else + if (check_kernel_mode) { +#endif + bool is_found = false; + typedef NTSTATUS (NTAPI tNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength); +#ifdef WIN_DRIVER + tNtQuerySystemInformation *nt_query_system_information = &NtQuerySystemInformation; +#else + tNtQuerySystemInformation *nt_query_system_information = reinterpret_cast<tNtQuerySystemInformation *>(InternalGetProcAddress(ntdll, VMProtectDecryptStringA("NtQuerySystemInformation"))); + if (nt_query_system_information) { +#endif + SYSTEM_KERNEL_DEBUGGER_INFORMATION info; + NTSTATUS status = nt_query_system_information(SystemKernelDebuggerInformation, &info, sizeof(info), NULL); + if (NT_SUCCESS(status) && info.DebuggerEnabled && !info.DebuggerNotPresent) + return true; + + SYSTEM_MODULE_INFORMATION *buffer = NULL; + ULONG buffer_size = 0; + /*status = */nt_query_system_information(SystemModuleInformation, &buffer, 0, &buffer_size); + if (buffer_size) { + buffer = reinterpret_cast<SYSTEM_MODULE_INFORMATION *>(new uint8_t[buffer_size * 2]); + status = nt_query_system_information(SystemModuleInformation, buffer, buffer_size * 2, NULL); + if (NT_SUCCESS(status)) { + for (size_t i = 0; i < buffer->Count && !is_found; i++) { + SYSTEM_MODULE_ENTRY *module_entry = &buffer->Module[i]; + char module_name[11]; + for (size_t j = 0; j < 5; j++) { + switch (j) { + case 0: + module_name[0] = 's'; + module_name[1] = 'i'; + module_name[2] = 'c'; + module_name[3] = 'e'; + module_name[4] = '.'; + module_name[5] = 's'; + module_name[6] = 'y'; + module_name[7] = 's'; + module_name[8] = 0; + break; + case 1: + module_name[0] = 's'; + module_name[1] = 'i'; + module_name[2] = 'w'; + module_name[3] = 'v'; + module_name[4] = 'i'; + module_name[5] = 'd'; + module_name[6] = '.'; + module_name[7] = 's'; + module_name[8] = 'y'; + module_name[9] = 's'; + module_name[10] = 0; + break; + case 2: + module_name[0] = 'n'; + module_name[1] = 't'; + module_name[2] = 'i'; + module_name[3] = 'c'; + module_name[4] = 'e'; + module_name[5] = '.'; + module_name[6] = 's'; + module_name[7] = 'y'; + module_name[8] = 's'; + module_name[9] = 0; + break; + case 3: + module_name[0] = 'i'; + module_name[1] = 'c'; + module_name[2] = 'e'; + module_name[3] = 'e'; + module_name[4] = 'x'; + module_name[5] = 't'; + module_name[6] = '.'; + module_name[7] = 's'; + module_name[8] = 'y'; + module_name[9] = 's'; + module_name[10] = 0; + break; + case 4: + module_name[0] = 's'; + module_name[1] = 'y'; + module_name[2] = 's'; + module_name[3] = 'e'; + module_name[4] = 'r'; + module_name[5] = '.'; + module_name[6] = 's'; + module_name[7] = 'y'; + module_name[8] = 's'; + module_name[9] = 0; + break; + } + if (_stricmp(module_entry->Name + module_entry->PathLength, module_name) == 0) { + is_found = true; + break; + } + } + } + } + delete [] buffer; + } +#ifndef WIN_DRIVER + } +#endif + if (is_found) + return true; + } +#endif + return false; +} + +bool WINAPI ExportedIsProtected() +{ + return true; +} + +#ifdef VMP_GNU +#elif defined(WIN_DRIVER) +#else + +/** + * VirtualObject + */ + +VirtualObject::VirtualObject(VirtualObjectType type, void *ref, HANDLE handle, uint32_t access) + : ref_(ref), handle_(handle), type_(type), file_position_(0), attributes_(0), access_(access) +{ + if(access & MAXIMUM_ALLOWED) + { + access_ |= KEY_ALL_ACCESS; + } +} + +VirtualObject::~VirtualObject() +{ + +} + +/** + * VirtualObjectList + */ + +VirtualObjectList::VirtualObjectList() +{ + CriticalSection::Init(critical_section_); +} + +VirtualObjectList::~VirtualObjectList() +{ + for (size_t i = 0; i < size(); i++) { + VirtualObject *object = v_[i]; + delete object; + } + v_.clear(); + + CriticalSection::Free(critical_section_); +} + +VirtualObject *VirtualObjectList::Add(VirtualObjectType type, void *ref, HANDLE handle, uint32_t access) +{ + VirtualObject *object = new VirtualObject(type, ref, handle, access); + v_.push_back(object); + return object; +} + +void VirtualObjectList::Delete(size_t index) +{ + VirtualObject *object = v_[index]; + v_.erase(index); + delete object; +} + +void VirtualObjectList::DeleteObject(HANDLE handle) +{ + handle = EXHANDLE(handle); + for (size_t i = size(); i > 0; i--) { + size_t index = i - 1; + VirtualObject *object = v_[index]; + if (object->handle() == handle) + Delete(index); + } +} + +void VirtualObjectList::DeleteRef(void *ref, HANDLE handle) +{ + handle = EXHANDLE(handle); + for (size_t i = size(); i > 0; i--) { + size_t index = i - 1; + VirtualObject *object = v_[index]; + if (object->ref() == ref && (!handle || object->handle() == handle)) + Delete(index); + } +} + +VirtualObject *VirtualObjectList::GetObject(HANDLE handle) const +{ + handle = EXHANDLE(handle); + for (size_t i = 0; i < size(); i++) { + VirtualObject *object = v_[i]; + if (object->handle() == handle) + return object; + } + return NULL; +} + +VirtualObject *VirtualObjectList::GetFile(HANDLE handle) const +{ + VirtualObject *object = GetObject(handle); + return (object && object->type() == OBJECT_FILE) ? object : NULL; +} + +VirtualObject *VirtualObjectList::GetSection(HANDLE handle) const +{ + VirtualObject *object = GetObject(handle); + return (object && object->type() == OBJECT_SECTION) ? object : NULL; +} + +VirtualObject *VirtualObjectList::GetMap(HANDLE process, void *map) const +{ + for (size_t i = 0; i < size(); i++) { + VirtualObject *object = v_[i]; + if (object->type() == OBJECT_MAP && object->handle() == process && object->ref() == map) + return object; + } + return NULL; +} + +VirtualObject *VirtualObjectList::GetKey(HANDLE handle) const +{ + VirtualObject *object = GetObject(handle); + return (object && object->type() == OBJECT_KEY) ? object : NULL; +} + +uint32_t VirtualObjectList::GetHandleCount(HANDLE handle) const +{ + uint32_t res = 0; + for (size_t i = 0; i < size(); i++) { + VirtualObject *object = v_[i]; + if (object->handle() == handle) + res++; + } + return res; +} + +uint32_t VirtualObjectList::GetPointerCount(const void *ref) const +{ + uint32_t res = 0; + for (size_t i = 0; i < size(); i++) { + VirtualObject *object = v_[i]; + if (object->ref() == ref) + res++; + } + return res; +} +#endif + +/** + * Core + */ + +Core *Core::self_ = NULL; + +Core::Core() + : string_manager_(NULL), licensing_manager_(NULL), hardware_id_(NULL) +#ifdef VMP_GNU +#elif defined(WIN_DRIVER) +#else + , resource_manager_(NULL), file_manager_(NULL), registry_manager_(NULL) + , hook_manager_(NULL), nt_protect_virtual_memory_(NULL), nt_close_(NULL) + , nt_query_object_(NULL), dbg_ui_remote_breakin_(NULL) +#endif +{ + +} + +Core::~Core() +{ + delete string_manager_; + delete licensing_manager_; + delete hardware_id_; + +#ifdef VMP_GNU +#elif defined(WIN_DRIVER) +#else + if (resource_manager_) { + resource_manager_->UnhookAPIs(*hook_manager_); + delete resource_manager_; + } + if (file_manager_) { + file_manager_->UnhookAPIs(*hook_manager_); + delete file_manager_; + } + if (registry_manager_) { + registry_manager_->UnhookAPIs(*hook_manager_); + delete registry_manager_; + } + + if (nt_protect_virtual_memory_ || nt_close_ || dbg_ui_remote_breakin_) + UnhookAPIs(*hook_manager_); + + delete hook_manager_; +#endif +} + +Core *Core::Instance() +{ + if (!self_) + self_ = new Core(); + return self_; +} + +void Core::Free() +{ + if (self_) { + delete self_; + self_ = NULL; + } +} + +struct CoreData { + uint32_t Strings; + uint32_t Resources; + uint32_t Storage; + uint32_t Registry; + uint32_t LicenseData; + uint32_t LicenseDataSize; + uint32_t TrialHWID; + uint32_t TrialHWIDSize; + uint32_t Key; + uint32_t Options; + + NOINLINE CoreData() + { + Strings = FACE_STRING_INFO; + Resources = FACE_RESOURCE_INFO; + Storage = FACE_STORAGE_INFO; + Registry = FACE_REGISTRY_INFO; + Key = FACE_KEY_INFO; + LicenseData = FACE_LICENSE_INFO; + LicenseDataSize = FACE_LICENSE_INFO_SIZE; + TrialHWID = FACE_TRIAL_HWID; + TrialHWIDSize = FACE_TRIAL_HWID_SIZE; + Options = FACE_CORE_OPTIONS; + } +}; + +bool Core::Init(HMODULE instance) +{ + const CoreData data; + + uint8_t *key = reinterpret_cast<uint8_t *>(instance) + data.Key; + if (data.Strings) + string_manager_ = new StringManager(reinterpret_cast<uint8_t *>(instance) + data.Strings, instance, key); + + if (data.LicenseData) + licensing_manager_ = new LicensingManager(reinterpret_cast<uint8_t *>(instance) + data.LicenseData, data.LicenseDataSize, key); + + if (data.TrialHWID) { + uint8_t hwid_data[64]; + { + CipherRC5 cipher(key); + cipher.Decrypt(reinterpret_cast<uint8_t *>(instance) + data.TrialHWID, reinterpret_cast<uint8_t *>(&hwid_data), sizeof(hwid_data)); + } + if (!hardware_id()->IsCorrect(hwid_data, data.TrialHWIDSize)) { + const VMP_CHAR *message; +#ifdef VMP_GNU + message = VMProtectDecryptStringA(MESSAGE_HWID_MISMATCHED_STR); +#else + message = VMProtectDecryptStringW(MESSAGE_HWID_MISMATCHED_STR); +#endif + ShowMessage(message); + return false; + } + } + +#ifdef VMP_GNU +#elif defined(WIN_DRIVER) +#else + if (data.Resources || data.Storage || data.Registry || (data.Options & (CORE_OPTION_MEMORY_PROTECTION | CORE_OPTION_CHECK_DEBUGGER))) + hook_manager_ = new HookManager(); + + if (data.Resources) { + resource_manager_ = new ResourceManager(reinterpret_cast<uint8_t *>(instance) + data.Resources, instance, key); + resource_manager_->HookAPIs(*hook_manager_); //-V595 + } + if (data.Storage) { + file_manager_ = new FileManager(reinterpret_cast<uint8_t *>(instance) + data.Storage, instance, key, &objects_); + file_manager_->HookAPIs(*hook_manager_); + } + if (data.Registry) { + registry_manager_ = new RegistryManager(reinterpret_cast<uint8_t *>(instance) + data.Registry, instance, key, &objects_); + registry_manager_->HookAPIs(*hook_manager_); + } + if (hook_manager_) + HookAPIs(*hook_manager_, data.Options); + if (file_manager_) { + if (!file_manager_->OpenFiles(*registry_manager_)) + return false; + } +#endif + + return true; +} + +HardwareID *Core::hardware_id() +{ + if (!hardware_id_) + hardware_id_ = new HardwareID; + return hardware_id_; +} + +#ifdef VMP_GNU +#elif defined(WIN_DRIVER) +#else +NTSTATUS WINAPI HookedNtProtectVirtualMemory(HANDLE ProcesssHandle, LPVOID *BaseAddress, SIZE_T *Size, DWORD NewProtect, PDWORD OldProtect) +{ + Core *core = Core::Instance(); + return core->NtProtectVirtualMemory(ProcesssHandle, BaseAddress, Size, NewProtect, OldProtect); +} + +void WINAPI HookedDbgUiRemoteBreakin() +{ + ::TerminateProcess(::GetCurrentProcess(), 0xDEADC0DE); +} + +NTSTATUS WINAPI HookedNtClose(HANDLE Handle) +{ + Core *core = Core::Instance(); + return core->NtClose(Handle); +} + +NTSTATUS WINAPI HookedNtQueryObject(HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength) +{ + Core *core = Core::Instance(); + return core->NtQueryObject(Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength, ReturnLength); +} + +void Core::HookAPIs(HookManager &hook_manager, uint32_t options) +{ + hook_manager.Begin(); + HMODULE dll = GetModuleHandleA(VMProtectDecryptStringA("ntdll.dll")); + if (options & CORE_OPTION_MEMORY_PROTECTION) + hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtProtectVirtualMemory"), &HookedNtProtectVirtualMemory, true, &nt_protect_virtual_memory_); + if (options & CORE_OPTION_CHECK_DEBUGGER) + dbg_ui_remote_breakin_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("DbgUiRemoteBreakin"), &HookedDbgUiRemoteBreakin, false); + if (file_manager_ || registry_manager_) { + nt_close_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtClose"), &HookedNtClose); + nt_query_object_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtQueryObject"), &HookedNtQueryObject); + } + hook_manager.End(); +} + +void Core::UnhookAPIs(HookManager &hook_manager) +{ + hook_manager.Begin(); + hook_manager.UnhookAPI(nt_protect_virtual_memory_); + hook_manager.UnhookAPI(nt_close_); + hook_manager.UnhookAPI(nt_query_object_); + hook_manager.UnhookAPI(dbg_ui_remote_breakin_); + hook_manager.End(); +} + +NTSTATUS Core::NtProtectVirtualMemory(HANDLE ProcesssHandle, LPVOID *BaseAddress, SIZE_T *Size, DWORD NewProtect, PDWORD OldProtect) +{ + if (ProcesssHandle == GetCurrentProcess()) { + const CRCData crc_data; + + uint8_t *image_base = crc_data.ImageBase; + size_t crc_image_size = loader_data->crc_image_size(); + try { + uint8_t *user_address = static_cast<uint8_t *>(*BaseAddress); + size_t user_size = *Size; + if (user_address + user_size > image_base && user_address < image_base + crc_image_size) { + uint8_t *crc_table = image_base + crc_data.Table; + uint32_t crc_table_size = *reinterpret_cast<uint32_t *>(image_base + crc_data.Size); + CRCValueCryptor crc_cryptor; + + // check regions + for (size_t i = 0; i < crc_table_size; i += sizeof(CRC_INFO)) { + CRC_INFO crc_info = *reinterpret_cast<CRC_INFO *>(crc_table + i); + crc_info.Address = crc_cryptor.Decrypt(crc_info.Address); + crc_info.Size = crc_cryptor.Decrypt(crc_info.Size); + crc_info.Hash = crc_cryptor.Decrypt(crc_info.Hash); + + uint8_t *crc_address = image_base + crc_info.Address; + if (user_address + user_size > crc_address && user_address < crc_address + crc_info.Size) + return STATUS_ACCESS_DENIED; + } + } + } catch(...) { + return STATUS_ACCESS_VIOLATION; + } + } + + return TrueNtProtectVirtualMemory(ProcesssHandle, BaseAddress, Size, NewProtect, OldProtect); +} + +NTSTATUS Core::NtClose(HANDLE Handle) +{ + { + CriticalSection cs(objects_.critical_section()); + + objects_.DeleteObject(Handle); + } + + return TrueNtClose(Handle); +} + +NTSTATUS Core::NtQueryObject(HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength) +{ + { + CriticalSection cs(objects_.critical_section()); + + VirtualObject *object = objects_.GetObject(Handle); + if (object) { + try { + switch (ObjectInformationClass) { + case ObjectBasicInformation: + { + if (ObjectInformationLength != sizeof(PUBLIC_OBJECT_BASIC_INFORMATION)) + return STATUS_INFO_LENGTH_MISMATCH; + + PUBLIC_OBJECT_BASIC_INFORMATION info = {}; + info.GrantedAccess = object->access(); + info.HandleCount = objects_.GetHandleCount(Handle); + info.PointerCount = objects_.GetPointerCount(object->ref()); + + if (ReturnLength) + *ReturnLength = sizeof(info); + } + return STATUS_SUCCESS; + default: + return STATUS_INVALID_PARAMETER; + } + } catch (...) { + return STATUS_ACCESS_VIOLATION; + } + } + } + + return TrueNtQueryObject(Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength, ReturnLength); +} + +NTSTATUS __forceinline Core::TrueNtProtectVirtualMemory(HANDLE ProcesssHandle, LPVOID *BaseAddress, SIZE_T *Size, DWORD NewProtect, PDWORD OldProtect) +{ + typedef NTSTATUS (WINAPI tNtProtectVirtualMemory)(HANDLE ProcesssHandle, LPVOID *BaseAddress, SIZE_T *Size, DWORD NewProtect, PDWORD OldProtect); + return reinterpret_cast<tNtProtectVirtualMemory *>(nt_protect_virtual_memory_)(ProcesssHandle, BaseAddress, Size, NewProtect, OldProtect); +} + +NTSTATUS __forceinline Core::TrueNtClose(HANDLE Handle) +{ + typedef NTSTATUS (WINAPI tNtClose)(HANDLE Handle); + return reinterpret_cast<tNtClose *>(nt_close_)(Handle); +} + +NTSTATUS __forceinline Core::TrueNtQueryObject(HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength) +{ + typedef NTSTATUS (WINAPI tNtQueryObject)(HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength); + return reinterpret_cast<tNtQueryObject *>(nt_query_object_)(Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength, ReturnLength); +} + +#endif
\ No newline at end of file diff --git a/runtime/core.h b/runtime/core.h new file mode 100644 index 0000000..04155fe --- /dev/null +++ b/runtime/core.h @@ -0,0 +1,149 @@ +#ifndef CORE_H +#define CORE_H + +class StringManager; +class LicensingManager; +class HardwareID; + +#ifdef VMP_GNU +#elif defined(WIN_DRIVER) +#else + +#ifndef NT_SUCCESS +#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) +#endif + +#ifndef NTDDI_WIN7 //SDK 6.0 +typedef enum _OBJECT_INFORMATION_CLASS { + ObjectBasicInformation = 0, + ObjectTypeInformation = 2 +} OBJECT_INFORMATION_CLASS; + +typedef struct _PUBLIC_OBJECT_BASIC_INFORMATION { + ULONG Attributes; + ACCESS_MASK GrantedAccess; + ULONG HandleCount; + ULONG PointerCount; + + ULONG Reserved[10]; // reserved for internal use + +} PUBLIC_OBJECT_BASIC_INFORMATION, *PPUBLIC_OBJECT_BASIC_INFORMATION; +#endif + +class ResourceManager; +class FileManager; +class RegistryManager; +class HookManager; + +enum VirtualObjectType { + OBJECT_FILE, + OBJECT_SECTION, + OBJECT_MAP, + OBJECT_KEY, +}; + +class VirtualObject +{ +public: + VirtualObject(VirtualObjectType type, void *ref, HANDLE handle, uint32_t access); + ~VirtualObject(); + void *ref() const { return ref_; } + VirtualObjectType type() const { return type_; } + HANDLE handle() const { return handle_; } + uint64_t file_position() const { return file_position_; } + void set_file_position(uint64_t position) { file_position_ = position; } + uint32_t attributes() const { return attributes_; } + void set_attributes(uint32_t attributes) { attributes_ = attributes; } + uint32_t access() const { return access_; } +private: + void *ref_; + HANDLE handle_; + VirtualObjectType type_; + uint64_t file_position_; + uint32_t attributes_; + uint32_t access_; +}; + +class VirtualObjectList +{ +public: + VirtualObjectList(); + ~VirtualObjectList(); + VirtualObject *Add(VirtualObjectType type, void *ref, HANDLE handle, uint32_t access); + void DeleteObject(HANDLE handle); + void DeleteRef(void *ref, HANDLE handle = 0); + VirtualObject *GetObject(HANDLE handle) const; + VirtualObject *GetFile(HANDLE handle) const; + VirtualObject *GetSection(HANDLE handle) const; + VirtualObject *GetMap(HANDLE process, void *map) const; + VirtualObject *GetKey(HANDLE handle) const; + VirtualObject *operator [] (size_t index) const { return v_[index]; } + size_t size() const { return v_.size(); } + CRITICAL_SECTION &critical_section() { return critical_section_; }; + uint32_t GetHandleCount(HANDLE handle) const; + uint32_t GetPointerCount(const void *ref) const; +private: + void Delete(size_t index); + CRITICAL_SECTION critical_section_; + vector<VirtualObject *> v_; +}; +#endif + +#ifdef VMP_GNU +EXPORT_API extern GlobalData *loader_data; +#else +extern GlobalData *loader_data; +#endif + +class Core +{ +public: + static Core *Instance(); + static void Free(); + bool Init(HMODULE instance); + ~Core(); + StringManager *string_manager() const { return string_manager_; } + LicensingManager *licensing_manager() const { return licensing_manager_; } + HardwareID *hardware_id(); +#ifdef VMP_GNU +#elif defined(WIN_DRIVER) +#else + NTSTATUS NtProtectVirtualMemory(HANDLE ProcesssHandle, LPVOID *BaseAddress, SIZE_T *Size, DWORD NewProtect, PDWORD OldProtect); + NTSTATUS NtClose(HANDLE Handle); + NTSTATUS NtQueryObject(HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength); + NTSTATUS TrueNtQueryObject(HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength); + ResourceManager *resource_manager() const { return resource_manager_; } + FileManager *file_manager() const { return file_manager_; } + RegistryManager *registry_manager() const { return registry_manager_; } +#endif +protected: + Core(); +private: + StringManager *string_manager_; + LicensingManager *licensing_manager_; + HardwareID *hardware_id_; +#ifdef VMP_GNU +#elif defined(WIN_DRIVER) +#else + NTSTATUS TrueNtProtectVirtualMemory(HANDLE ProcesssHandle, LPVOID *BaseAddress, SIZE_T *Size, DWORD NewProtect, PDWORD OldProtect); + NTSTATUS TrueNtClose(HANDLE Handle); + void HookAPIs(HookManager &hook_manager, uint32_t options); + void UnhookAPIs(HookManager &hook_manager); + VirtualObjectList objects_; + ResourceManager *resource_manager_; + FileManager *file_manager_; + RegistryManager *registry_manager_; + HookManager *hook_manager_; + void *nt_protect_virtual_memory_; + void *nt_close_; + void *nt_query_object_; + void *dbg_ui_remote_breakin_; +#endif + static Core *self_; + + // no copy ctr or assignment op + Core(const Core &); + Core &operator=(const Core &); +}; + +#endif
\ No newline at end of file diff --git a/runtime/crypto.cc b/runtime/crypto.cc new file mode 100644 index 0000000..d4e7675 --- /dev/null +++ b/runtime/crypto.cc @@ -0,0 +1,1086 @@ +#include "common.h" +#include "crypto.h" + +uint32_t rand32() +{ + uint32_t v1 = rand(); + uint32_t v2 = rand(); + return (v1 << 16) | v2; +} + +uint64_t rand64() +{ + uint64_t v1 = rand32(); + uint64_t v2 = rand32(); + return (v1 << 32) | v2; +} + +/** + * CipherRC5 + */ + +CipherRC5::CipherRC5(const RC5Key &key) +{ +#ifndef RUNTIME + P = key.P; + Q = key.Q; +#endif + + uint32_t i, j, k, u = w / 8, A, B, L[c]; + + for (i = b - 1, L[c - 1] = 0; i != (uint32_t)-1; i--) //-V621 + L[i / u] = (L[i / u] << 8) + key.Value[i]; + + for (S[0] = P, i = 1; i < t; i++) + S[i] = S[i - 1] + Q; + for (A = B = i = j = k = 0; k < 3 * t; k++, i = (i + 1) % t, j = (j + 1) % c) /* 3*t > 3*c */ + { + A = S[i] = _rotl32(S[i] + (A + B), 3); + B = L[j] = _rotl32(L[j] + (A + B), (A + B)); + } +} + +void CipherRC5::Encrypt(const uint32_t *in, uint32_t *out) const +{ + uint32_t i, A = in[0] + S[0], B = in[1] + S[1]; + for (i = 1; i <= r; i++) + { + A = _rotl32(A ^ B, B) + S[2 * i]; + B = _rotl32(B ^ A, A) + S[2 * i + 1]; + } + out[0] = A; + out[1] = B; +} + +void CipherRC5::Decrypt(const uint32_t *in, uint32_t *out) const +{ + uint32_t i, B = in[1], A = in[0]; + for (i = r; i > 0; i--) { + B = _rotr32(B - S[2 * i + 1], A) ^ A; + A = _rotr32(A - S[2 * i], B) ^ B; + } + out[1] = B - S[1]; + out[0] = A - S[0]; +} + +void CipherRC5::Encrypt(uint8_t *buff, size_t count) const +{ + for (size_t i = 0; i < count; i += 8) { + Encrypt(reinterpret_cast<uint32_t *>(buff + i), reinterpret_cast<uint32_t *>(buff + i)); + } +} + +void CipherRC5::Decrypt(const uint8_t *in, uint8_t *out, size_t count) const +{ + for (size_t i = 0; i < count; i += 8) { + Decrypt(reinterpret_cast<const uint32_t *>(in + i), reinterpret_cast<uint32_t *>(out + i)); + } +} + +/** + * RC5Key + */ + +void RC5Key::Create() +{ +#ifdef RUNTIME + uint64_t key = __rdtsc(); + key ^= ~key << 32; + uint8_t *p = reinterpret_cast<uint8_t *>(&key); + for (size_t i = 0; i < _countof(Value); i++) { + Value[i] = p[i]; + } +#else + for (size_t i = 0; i < _countof(Value); i++) { + Value[i] = rand(); + } + P = rand32(); + Q = rand32(); +#endif +} + +/** + * BigNumber + */ + +BigNumber::BigNumber() +{ + init(0); +} + +BigNumber::BigNumber(const uint8_t *data, size_t size, bool inverse_order) +{ + size_t w, i; + + w = (size + BIGNUM_INT_BYTES - 1) / BIGNUM_INT_BYTES; /* bytes->words */ + init(w); + + if (inverse_order) { + if (size) + memcpy(&data_[1], data, size); + } else { + for (i = size; i--;) { + uint8_t byte = *data++; + bignum_set_word(data_ + 1 + i / BIGNUM_INT_BYTES, bignum_get_word(data_ + 1 + i / BIGNUM_INT_BYTES) | byte << (8*i % BIGNUM_INT_BITS)); + } + } + + while (bignum_get_word(data_ + 0) > 1 && bignum_get_word(data_ + bignum_get_word(data_ + 0)) == 0) + bignum_set_word(data_ + 0, bignum_get_word(data_ + 0) - 1); +} + +BigNumber::BigNumber(const BigNumber &src) +{ + size_t size = src.data(0); + init(size); + for (size_t i = 1; i <= size; i++) { + bignum_set_word(data_ + i, src.data(i)); + } +} + +BigNumber::BigNumber(Bignum data, const BignumInt *salt) +{ + data_ = data; +#ifdef RUNTIME + for (size_t i = 0; i < _countof(salt_); i++) { + salt_[i] = salt[i]; + } +#endif +} + +BigNumber::~BigNumber() +{ + delete [] data_; +} + +bool BigNumber::operator < (const BigNumber &b) const +{ + return (bignum_cmp(b) < 0); +} + +size_t BigNumber::size() const +{ + return data(0) * BIGNUM_INT_BYTES; +} + +uint8_t BigNumber::operator [] (size_t index) const +{ + return bignum_byte(data_, index); +} + +#define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2) +#define DIVMOD_WORD(q, r, hi, lo, w) { \ + BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \ + q = n / w; \ + r = n % w; \ +} + +BignumInt BigNumber::bignum_get_word(Bignum b) const +{ +#ifdef RUNTIME + size_t addr = reinterpret_cast<size_t>(b); + size_t offset = (addr + (addr >> 7)) % _countof(salt_); + size_t salt = salt_[offset] + 0x73 + (addr >> 4); + return static_cast<BignumInt>((*b ^ salt) + addr); +#else + return *b; +#endif +} + +void BigNumber::bignum_set_word(Bignum b, BignumInt value) const +{ +#ifdef RUNTIME + size_t addr = reinterpret_cast<size_t>(b); + size_t offset = (addr + (addr >> 7)) % _countof(salt_); + size_t salt = salt_[offset] + 0x73 + (addr >> 4); + *b = static_cast<BignumInt>((value - addr) ^ salt); +#else + *b = value; +#endif +} + +void BigNumber::init(size_t length) +{ + data_ = new BignumInt[length + 1]; + +#ifdef RUNTIME + { + uint64_t rand = __rdtsc(); + SHA1 hash; + hash.Input(reinterpret_cast<const uint8_t *>(&rand), sizeof(rand)); + hash.Input(reinterpret_cast<const uint8_t *>(&data_), sizeof(data_)); + + const BignumInt *p = reinterpret_cast<const BignumInt *>(hash.Result()); + for (size_t i = 0; i < _countof(salt_); i++) { + salt_[i] = p[i]; + } + } +#endif + + bignum_set_word(data_, (BignumInt)length); + for (size_t i = 1; i <= length; i++) + bignum_set_word(data_ + i, 0); +} + +void BigNumber::internal_mul(BignumInt *a, BignumInt *b, BignumInt *c, int len) const +{ + int i, j; + BignumDblInt t; + + for (j = 0; j < 2 * len; j++) + bignum_set_word(c + j, 0); + + for (i = len - 1; i >= 0; i--) { + t = 0; + for (j = len - 1; j >= 0; j--) { + t += MUL_WORD(bignum_get_word(a + i), (BignumDblInt) bignum_get_word(b + j)); + t += (BignumDblInt) bignum_get_word(c + i + j + 1); + bignum_set_word(c + i + j + 1, (BignumInt) t); + t = t >> BIGNUM_INT_BITS; + } + bignum_set_word(c + i, (BignumInt) t); + } +} + +void BigNumber::internal_add_shifted(BignumInt *number, unsigned n, int shift) const +{ + int word = 1 + (shift / BIGNUM_INT_BITS); + int bshift = shift % BIGNUM_INT_BITS; + BignumDblInt addend; + + addend = (BignumDblInt)n << bshift; + + while (addend) { + addend += bignum_get_word(number + word); + bignum_set_word(number + word, (BignumInt) addend & BIGNUM_INT_MASK); + addend >>= BIGNUM_INT_BITS; + word++; + } +} + +void BigNumber::internal_mod(BignumInt *a, int alen, + BignumInt *m, int mlen, + BignumInt *quot, int qshift) const +{ + BignumInt m0, m1; + unsigned int h; + int i, k; + + m0 = bignum_get_word(m + 0); + m1 = (mlen > 1) ? bignum_get_word(m + 1) : 0; + + for (i = 0; i <= alen - mlen; i++) { + BignumDblInt t; + unsigned int q, r, c, ai1; + + if (i == 0) { + h = 0; + } else { + h = bignum_get_word(a + i - 1); + bignum_set_word(a + i - 1, 0); + } + + if (i == alen - 1) + ai1 = 0; + else + ai1 = bignum_get_word(a + i + 1); + + /* Find q = h:a[i] / m0 */ + DIVMOD_WORD(q, r, h, bignum_get_word(a + i), m0); + + /* Refine our estimate of q by looking at h:a[i]:a[i+1] / m0:m1 */ + t = MUL_WORD(m1, q); + if (t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) { + q--; + t -= m1; + r = (r + m0) & BIGNUM_INT_MASK; /* overflow? */ + if (r >= (BignumDblInt) m0 && + t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) q--; + } + + /* Subtract q * m from a[i...] */ + c = 0; + for (k = mlen - 1; k >= 0; k--) { + t = MUL_WORD(q, bignum_get_word(m + k)); + t += c; + c = t >> BIGNUM_INT_BITS; + if ((BignumInt) t > bignum_get_word(a + i + k)) + c++; + bignum_set_word(a + i + k, bignum_get_word(a + i + k) - (BignumInt) t); + } + + /* Add back m in case of borrow */ + if (c != h) { + t = 0; + for (k = mlen - 1; k >= 0; k--) { + t += bignum_get_word(m + k); + t += bignum_get_word(a + i + k); + bignum_set_word(a + i + k, (BignumInt) t); + t = t >> BIGNUM_INT_BITS; + } + q--; + } + if (quot) + internal_add_shifted(quot, q, qshift + BIGNUM_INT_BITS * (alen - mlen - i)); + } +} + +BigNumber BigNumber::modpow(const BigNumber &exp, const BigNumber &mod) const +{ + BignumInt *a, *b, *n, *m; + int mshift; + int i,j,mlen; + Bignum result; + + /* Allocate m of size mlen, copy mod to m */ + /* We use big endian internally */ + mlen = mod.data(0); +#ifdef WIN_DRIVER + NT_ASSERT(mlen > 0); +#else + assert(mlen > 0); +#endif + if(mlen <= 0) return BigNumber(); + + m = new BignumInt[mlen]; + for (j = 0; j < mlen; j++) + bignum_set_word(m + j, mod.data(mlen - j)); + + /* Shift m left to make msb bit set */ + for (mshift = 0; mshift < BIGNUM_INT_BITS-1; mshift++) + if ((bignum_get_word(m + 0) << mshift) & BIGNUM_TOP_BIT) + break; + if (mshift) { + for (i = 0; i < mlen - 1; i++) + m[i] = (bignum_get_word(m + i) << mshift) | (bignum_get_word(m + i + 1) >> (BIGNUM_INT_BITS - mshift)); + bignum_set_word(m + mlen - 1, bignum_get_word(m + mlen - 1) << mshift); + } + + /* Allocate n of size mlen, copy base to n */ + int blen = data(0); + n = new BignumInt[mlen]; + i = mlen - blen; + for (j = 0; j < i; j++) + bignum_set_word(n + j, 0); + for (j = 0; j < blen; j++) + bignum_set_word(n + i + j, data(blen - j)); + + /* Allocate a and b of size 2*mlen. Set a = 1 */ + a = new BignumInt[2 * mlen]; + b = new BignumInt[2 * mlen]; + for (i = 0; i < 2 * mlen; i++) + bignum_set_word(a + i, 0); + bignum_set_word(a + 2 * mlen - 1, 1); + + /* Skip leading zero bits of exp. */ + i = 0; + j = BIGNUM_INT_BITS-1; + int elen = exp.data(0); + while (i < elen && (exp.data(elen - i) & (1 << j)) == 0) { + j--; + if (j < 0) { + i++; + j = BIGNUM_INT_BITS-1; + } + } + + /* Main computation */ + while (i < elen) { + while (j >= 0) { + internal_mul(a + mlen, a + mlen, b, mlen); + internal_mod(b, mlen * 2, m, mlen, NULL, 0); + if ((exp.data(elen - i) & (1 << j)) != 0) { + internal_mul(b + mlen, n, a, mlen); + internal_mod(a, mlen * 2, m, mlen, NULL, 0); + } else { + BignumInt *t; + t = a; + a = b; + b = t; + } + j--; + } + i++; + j = BIGNUM_INT_BITS-1; + } + + /* Fixup result in case the modulus was shifted */ + if (mshift) { + for (i = mlen - 1; i < 2 * mlen - 1; i++) + a[i] = (bignum_get_word(a + i) << mshift) | (bignum_get_word(a + i + 1) >> (BIGNUM_INT_BITS - mshift)); + bignum_set_word(a + 2 * mlen - 1, bignum_get_word(a + 2 * mlen - 1) << mshift); + internal_mod(a, mlen * 2, m, mlen, NULL, 0); + for (i = 2 * mlen - 1; i >= mlen; i--) + bignum_set_word(a + i, (bignum_get_word(a + i) >> mshift) | (bignum_get_word(a + i - 1) << (BIGNUM_INT_BITS - mshift))); + } + + /* Copy result to buffer */ + result = new BignumInt[mlen + 1]; + bignum_set_word(result, (BignumInt)mlen); + for (i = 0; i < mlen; i++) + bignum_set_word(result + mlen - i, bignum_get_word(a + i + mlen)); + while (bignum_get_word(result + 0) > 1 && bignum_get_word(result + bignum_get_word(result + 0)) == 0) + bignum_set_word(result + 0, bignum_get_word(result + 0) - 1); + + /* Free temporary arrays */ + delete [] a; + delete [] b; + delete [] m; + delete [] n; + + return BigNumber(result, +#ifdef RUNTIME + salt_ +#else + NULL +#endif + ); +} + +CryptoContainer *BigNumber::modpow(const CryptoContainer &source, size_t exp_offset, size_t exp_size, size_t mod_offset, size_t mod_size) const +{ + BignumInt *a, *b, *n, *m, *e, *mem, *next; + int mshift; + int i, j, mlen, elen, blen; + Bignum result; + size_t k; + size_t arrays[5]; + + mlen = (int)(mod_size + BIGNUM_INT_BYTES - 1) / BIGNUM_INT_BYTES; + elen = (int)(exp_size + BIGNUM_INT_BYTES - 1) / BIGNUM_INT_BYTES; + +#ifdef WIN_DRIVER + NT_ASSERT(mlen > 0); +#else + assert(mlen > 0); +#endif + if (mlen <= 0 || data(0) > mlen) return NULL; + + for (k = 0; k < _countof(arrays); k++) { + arrays[k] = k; + } + for (k = 0; k < _countof(arrays); k++) { + uint64_t rand = __rdtsc(); + size_t r = static_cast<size_t>(rand ^ (rand >> 32)) % _countof(arrays); + size_t t = arrays[k]; + arrays[k] = arrays[r]; + arrays[r] = t; + } + + // Allocate memory for temporary arrays + mem = new BignumInt[mlen + mlen + mlen * 2 + mlen * 2 + elen]; + next = mem; + for (k = 0; k < _countof(arrays); k++) { + switch (arrays[k]) { + case 0: + /* Allocate m of size mlen, copy mod to m */ + m = next; + next = m + mlen; + + for (j = 0; j < mlen; j++) { + BignumInt value = 0; + for (i = 0; i < BIGNUM_INT_BYTES; i++) { + value = (value << 8) | source.GetByte(mod_offset++); + } + bignum_set_word(m + j, value); + } + + /* Shift m left to make msb bit set */ + for (mshift = 0; mshift < BIGNUM_INT_BITS - 1; mshift++) + if ((bignum_get_word(m + 0) << mshift) & BIGNUM_TOP_BIT) + break; + if (mshift) { + for (i = 0; i < mlen - 1; i++) + m[i] = (bignum_get_word(m + i) << mshift) | (bignum_get_word(m + i + 1) >> (BIGNUM_INT_BITS - mshift)); + bignum_set_word(m + mlen - 1, bignum_get_word(m + mlen - 1) << mshift); + } + break; + + case 1: + /* Allocate e of size elen, copy exp to e */ + e = next; + next = next + elen; + + for (j = 0; j < elen; j++) { + BignumInt value = 0; + for (i = 0; i < BIGNUM_INT_BYTES; i++) { + value = (value << 8) | source.GetByte(exp_offset++); + } + bignum_set_word(e + j, value); + } + break; + + case 2: + /* Allocate n of size mlen, copy base to n */ + n = next; + next = next + mlen; + + blen = data(0); + i = mlen - blen; + for (j = 0; j < i; j++) + bignum_set_word(n + j, 0); + for (j = 0; j < blen; j++) + bignum_set_word(n + i + j, data(blen - j)); + break; + + case 3: + /* Allocate a of size 2*mlen. Set a = 1 */ + a = next; + next = next + 2 * mlen; + + for (i = 0; i < 2 * mlen; i++) + bignum_set_word(a + i, 0); + bignum_set_word(a + 2 * mlen - 1, 1); + break; + + case 4: + /* Allocate b of size 2*mlen */ + b = next; + next = next + 2 * mlen; + break; + } + } + + /* Skip leading zero bits of exp. */ + i = 0; + j = BIGNUM_INT_BITS - 1; + while (i < elen && (bignum_get_word(e + i) & (1 << j)) == 0) { + j--; + if (j < 0) { + i++; + j = BIGNUM_INT_BITS - 1; + } + } + + /* Main computation */ + while (i < elen) { + while (j >= 0) { + internal_mul(a + mlen, a + mlen, b, mlen); + internal_mod(b, mlen * 2, m, mlen, NULL, 0); + if ((bignum_get_word(e + i) & (1 << j)) != 0) { + internal_mul(b + mlen, n, a, mlen); + internal_mod(a, mlen * 2, m, mlen, NULL, 0); + } + else { + BignumInt *t; + t = a; + a = b; + b = t; + } + j--; + } + i++; + j = BIGNUM_INT_BITS - 1; + } + + /* Fixup result in case the modulus was shifted */ + if (mshift) { + for (i = mlen - 1; i < 2 * mlen - 1; i++) + a[i] = (bignum_get_word(a + i) << mshift) | (bignum_get_word(a + i + 1) >> (BIGNUM_INT_BITS - mshift)); + bignum_set_word(a + 2 * mlen - 1, bignum_get_word(a + 2 * mlen - 1) << mshift); + internal_mod(a, mlen * 2, m, mlen, NULL, 0); + for (i = 2 * mlen - 1; i >= mlen; i--) + bignum_set_word(a + i, (bignum_get_word(a + i) >> mshift) | (bignum_get_word(a + i - 1) << (BIGNUM_INT_BITS - mshift))); + } + + /* Copy result to buffer */ + result = b; + for (i = 0; i < mlen; i++) + bignum_set_word(result + mlen - i, bignum_get_word(a + i + mlen)); + while (mlen > 1 && bignum_get_word(result + mlen) == 0) + mlen--; + bignum_set_word(result, (BignumInt)mlen); + + size_t size = bignum_get_word(result + 0) * BIGNUM_INT_BYTES; + RC5Key key; + key.Create(); + CryptoContainer *res = new CryptoContainer(size, key); + for (k = 0; k < size; k++) { + // BigNumber has inverse order of bytes + res->SetByte(k, bignum_byte(result, size - 1 - k)); + } + + /* Free temporary arrays */ + delete[] mem; + + return res; +} + +NOINLINE uint8_t BigNumber::bignum_byte(Bignum bn, size_t i) const +{ + if (i >= BIGNUM_INT_BYTES * (size_t)bignum_get_word(bn + 0)) + return 0; /* beyond the end */ + else + return (bignum_get_word(bn + i / BIGNUM_INT_BYTES + 1) >> + ((i % BIGNUM_INT_BYTES)*8)) & 0xFF; +} + +int BigNumber::bignum_cmp(const BigNumber &b) const +{ + int amax = data(0), bmax = b.data(0); + int i = (amax > bmax ? amax : bmax); + while (i) { + BignumInt aval = (i > amax ? 0 : data(i)); + BignumInt bval = (i > bmax ? 0 : b.data(i)); + if (aval < bval) + return -1; + if (aval > bval) + return +1; + i--; + } + return 0; +} + +/** + * CryptoContainer + */ + +CryptoContainer::CryptoContainer(size_t size, const RC5Key &key) + : is_own_data_(true), size_(size) +{ + // align size + size = (size + RC5_BLOCK_SIZE - 1) / RC5_BLOCK_SIZE * RC5_BLOCK_SIZE; + data_ = new uint32_t[size / sizeof(uint32_t)]; + cipher_ = new CipherRC5(key); +} + +CryptoContainer::CryptoContainer(uint8_t *data, size_t size, const RC5Key &key) + : is_own_data_(false), data_(reinterpret_cast<uint32_t *>(data)), size_(size) +{ + cipher_ = new CipherRC5(key); +} + +CryptoContainer::CryptoContainer(const BigNumber &bn) + : is_own_data_(true) +{ + RC5Key key; + key.Create(); + cipher_ = new CipherRC5(key); + + // align size + size_t len = bn.size(); + size_ = (len + RC5_BLOCK_SIZE - 1) / RC5_BLOCK_SIZE * RC5_BLOCK_SIZE; + data_ = new uint32_t[size_ / sizeof(uint32_t)]; + + for (size_t i = 0; i < len; i++) { + // BigNumber has inverse order of bytes + SetByte(i, bn[len - 1 - i]); + } +} + +CryptoContainer::~CryptoContainer() +{ + delete cipher_; + if (is_own_data_) + delete [] data_; +} + +bool CryptoContainer::EncryptValue(size_t pos, uint8_t *value, size_t value_size) const +{ + if (pos > size_ - value_size) + return false; + + uint32_t buff[4]; + size_t block_pos = pos / RC5_BLOCK_SIZE; + pos = pos % RC5_BLOCK_SIZE; + size_t block_count = (pos <= RC5_BLOCK_SIZE - value_size) ? 1 : 2; + for (size_t i = 0; i < block_count; i++) { + cipher_->Decrypt(&data_[block_pos * 2 + i * 2], &buff[i * 2]); + } + uint8_t *p = reinterpret_cast<uint8_t *>(buff); + for (size_t i = 0; i < value_size; i++) { + p[pos + i] = value[i]; + } + for (size_t i = 0; i < block_count; i++) { + cipher_->Encrypt(&buff[i * 2], &data_[block_pos * 2 + i * 2]); + } + return true; +} + +bool CryptoContainer::DecryptValue(size_t pos, uint8_t *value, size_t value_size) const +{ + if (pos > size_ - value_size) + return false; + + uint32_t buff[4]; + size_t block_pos = pos / RC5_BLOCK_SIZE; + pos = pos % RC5_BLOCK_SIZE; + size_t block_count = (pos <= RC5_BLOCK_SIZE - value_size) ? 1 : 2; + for (size_t i = 0; i < block_count; i++) { + cipher_->Decrypt(&data_[block_pos * 2 + i * 2], &buff[i * 2]); + } + uint8_t *p = reinterpret_cast<uint8_t *>(buff); + for (size_t i = 0; i < value_size; i++) { + value[i] = p[pos + i]; + } + return true; +} + +uint32_t CryptoContainer::GetDWord(size_t pos) const +{ + uint32_t res; + if (DecryptValue(pos, reinterpret_cast<uint8_t *>(&res), sizeof(res))) + return res; + return -1; +} + +uint16_t CryptoContainer::GetWord(size_t pos) const +{ + uint16_t res; + if (DecryptValue(pos, reinterpret_cast<uint8_t *>(&res), sizeof(res))) + return res; + return -1; +} + +uint8_t CryptoContainer::GetByte(size_t pos) const +{ + uint8_t res; + if (DecryptValue(pos, reinterpret_cast<uint8_t *>(&res), sizeof(res))) + return res; + return -1; +} + +uint64_t CryptoContainer::GetQWord(size_t pos) const +{ + uint64_t res; + if (DecryptValue(pos, reinterpret_cast<uint8_t *>(&res), sizeof(res))) + return res; + return -1; +} + +bool CryptoContainer::SetDWord(size_t pos, uint32_t value) const +{ + return EncryptValue(pos, reinterpret_cast<uint8_t *>(&value), sizeof(value)); +} + +bool CryptoContainer::SetWord(size_t pos, uint16_t value) const +{ + return EncryptValue(pos, reinterpret_cast<uint8_t *>(&value), sizeof(value)); +} + +bool CryptoContainer::SetByte(size_t pos, uint8_t value) const +{ + return EncryptValue(pos, reinterpret_cast<uint8_t *>(&value), sizeof(value)); +} + +static const uint8_t utf8_limits[5] = {0xC0, 0xE0, 0xF0, 0xF8, 0xFC}; + +void CryptoContainer::UTF8ToUnicode(size_t offset, size_t len, VMP_WCHAR *dest, size_t dest_size) const +{ + if (!dest || dest_size == 0) return; // nothing to do + + size_t pos = 0; + size_t dest_pos = 0; + while (pos < len && dest_pos < dest_size) { + uint8_t b = GetByte(offset + pos++); + + if (b < 0x80) { + dest[dest_pos++] = b; + continue; + } + + size_t val_len; + for (val_len = 0; val_len < _countof(utf8_limits); val_len++) { + if (b < utf8_limits[val_len]) + break; + } + + if (val_len == 0) + continue; + + uint32_t value = b - utf8_limits[val_len - 1]; + for (size_t i = 0; i < val_len; i++) { + if (pos == len) + break; + b = GetByte(offset + pos++); + if (b < 0x80 || b >= 0xC0) + break; + value <<= 6; + value |= (b - 0x80); + } + + if (value < 0x10000) { + dest[dest_pos++] = static_cast<uint16_t>(value); + } else if (value <= 0x10FFFF) { + value -= 0x10000; + dest[dest_pos++] = static_cast<uint16_t>(0xD800 + (value >> 10)); + dest[dest_pos++] = static_cast<uint16_t>(0xDC00 + (value & 0x3FF)); + } + } + + if (dest_pos < dest_size - 1) + dest[dest_pos] = 0; + else + dest[dest_pos - 1] = 0; +} + +/** + * Base64 + */ + +bool Base64Encode(const uint8_t *src, size_t src_len, char *dst, size_t &dst_len) +{ + if (!src || !dst) + return false; + + const char alphabet[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; + + const char padchar = '='; + size_t padlen = 0; + + char *out = dst; + char *dst_end = dst + dst_len; + size_t i = 0; + while (i < src_len) { + uint32_t chunk = 0; + chunk |= static_cast<uint32_t>(src[i++]) << 16; + if (i == src_len) { + padlen = 2; + } else { + chunk |= static_cast<uint32_t>(src[i++]) << 8; + if (i == src_len) { + padlen = 1; + } else { + chunk |= static_cast<uint32_t>(src[i++]); + } + } + + size_t j = (chunk & 0x00fc0000) >> 18; + size_t k = (chunk & 0x0003f000) >> 12; + size_t l = (chunk & 0x00000fc0) >> 6; + size_t m = (chunk & 0x0000003f); + + if (out + 4 > dst_end) + return false; + + *out++ = alphabet[j]; + *out++ = alphabet[k]; + if (padlen > 1) *out++ = padchar; + else *out++ = alphabet[l]; + if (padlen > 0) *out++ = padchar; + else *out++ = alphabet[m]; + } + + dst_len = out - dst; + return true; +} + +size_t Base64EncodeGetRequiredLength(size_t src_len) +{ + return src_len * 4 / 3 + 3; +} + +bool Base64Decode(const char *src, size_t src_len, uint8_t *dst, size_t &dst_len) +{ + if (!src || !dst) + return false; + + size_t buf = 0; + size_t nbits = 0; + size_t offset = 0; + for (size_t i = 0; i < src_len; ++i) { + char c = src[i]; + int d; + + if (c >= 'A' && c <= 'Z') { + d = c - 'A'; + } else if (c >= 'a' && c <= 'z') { + d = c - 'a' + 26; + } else if (c >= '0' && c <= '9') { + d = c - '0' + 52; + } else if (c == '+') { + d = 62; + } else if (c == '/') { + d = 63; + } else { + d = -1; + } + + if (d != -1) { + buf = (buf << 6) | d; + nbits += 6; + if (nbits >= 8) { + nbits -= 8; + if (offset == dst_len) + return false; + dst[offset++] = static_cast<uint8_t>(buf >> nbits); + buf &= size_t((1 << nbits) - 1); + } + } + } + + dst_len = offset; + return true; +} + +/** + * SHA1 + */ + +SHA1::SHA1() +{ + Reset(); +} + +void SHA1::Reset() +{ + length_low_ = 0; + length_high_ = 0; + message_block_index_ = 0; + hash_[0] = 0x67452301; + hash_[1] = 0xEFCDAB89; + hash_[2] = 0x98BADCFE; + hash_[3] = 0x10325476; + hash_[4] = 0xC3D2E1F0; + computed_ = false; +} + +void SHA1::Input(const uint8_t *data, size_t size) +{ + if (computed_) + return; + + for (size_t i = 0; i < size; i++) { + message_block_[message_block_index_++] = data[i]; + length_low_ += 8; + if (!length_low_) { + // value out of DWORD + length_high_++; + } + if (message_block_index_ == 64) + ProcessMessageBlock(); + } +} + +void SHA1::Input(const CryptoContainer &data, size_t offset, size_t size) +{ + if (computed_) + return; + + for (size_t i = 0; i < size; i++) { + message_block_[message_block_index_++] = data.GetByte(offset + i); + length_low_ += 8; + if (!length_low_) { + // value out of DWORD + length_high_++; + } + if (message_block_index_ == 64) + ProcessMessageBlock(); + } +} + +void SHA1::ProcessMessageBlock() +{ + size_t t; + uint32_t temp, W[80], A, B, C, D, E; + + for (t = 0; t < 16; t++) { + W[t] = __builtin_bswap32(*reinterpret_cast<uint32_t *>(&message_block_[t * 4])); + } + + for (t = 16; t < 80; t++) { + W[t] = _rotl32(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1); + } + + A = hash_[0]; + B = hash_[1]; + C = hash_[2]; + D = hash_[3]; + E = hash_[4]; + + for (t = 0; t < 20; t++) { + temp = _rotl32(A, 5) + ((B & C) | ((~B) & D)) + E + W[t] + 0x5A827999; + E = D; + D = C; + C = _rotl32(B, 30); + B = A; + A = temp; + } + + for(t = 20; t < 40; t++) { + temp = _rotl32(A, 5) + (B ^ C ^ D) + E + W[t] + 0x6ED9EBA1; + E = D; + D = C; + C = _rotl32(B, 30); + B = A; + A = temp; + } + + for (t = 40; t < 60; t++) { + temp = _rotl32(A, 5) + ((B & C) | (B & D) | (C & D)) + E + W[t] + 0x8F1BBCDC; + E = D; + D = C; + C = _rotl32(B, 30); + B = A; + A = temp; + } + + for(t = 60; t < 80; t++) { + temp = _rotl32(A, 5) + (B ^ C ^ D) + E + W[t] + 0xCA62C1D6; + E = D; + D = C; + C = _rotl32(B, 30); + B = A; + A = temp; + } + + hash_[0] += A; + hash_[1] += B; + hash_[2] += C; + hash_[3] += D; + hash_[4] += E; + + message_block_index_ = 0; +} + +void SHA1::PadMessage() +{ + message_block_[message_block_index_++] = 0x80; + if (message_block_index_ > 56) { + for (size_t i = message_block_index_; i < _countof(message_block_); i++) { + message_block_[i] = 0; + } + ProcessMessageBlock(); + } + for (size_t i = message_block_index_; i < 56; i++) { + message_block_[i] = 0; + } + + *reinterpret_cast<uint32_t *>(&message_block_[56]) = __builtin_bswap32(length_high_); + *reinterpret_cast<uint32_t *>(&message_block_[60]) = __builtin_bswap32(length_low_); + + ProcessMessageBlock(); +} + +const uint8_t * SHA1::Result() +{ + if (!computed_) { + PadMessage(); + computed_ = true; + } + + for (size_t i = 0; i < _countof(hash_); i++) { + digest_[i] = __builtin_bswap32(hash_[i]); + } + return reinterpret_cast<const uint8_t *>(&digest_[0]); +} + +/** + * CRC32 + */ + +#ifdef RUNTIME +NOINLINE EXPORT_API uint32_t WINAPI CalcCRC(const void *key, size_t len) +#else +uint32_t CalcCRC(const void * key, size_t len) +#endif +{ + uint32_t crc = 0; + const uint8_t *p = static_cast<const uint8_t *>(key); + while (len--) { + crc = crc32_table[(crc ^ *p++) & 0xFF] ^ (crc >> 8); + } + return ~crc; +}
\ No newline at end of file diff --git a/runtime/crypto.h b/runtime/crypto.h new file mode 100644 index 0000000..970061b --- /dev/null +++ b/runtime/crypto.h @@ -0,0 +1,388 @@ +#ifndef CRYPTO_H +#define CRYPTO_H + +#include "common.h" + +uint32_t rand32(); +uint64_t rand64(); + +#ifdef VMP_GNU + +inline uint8_t _rotl8(uint8_t value, int shift) +{ + __asm__ __volatile__ ("rolb %%cl, %0" + : "=r"(value) + : "0"(value), "c"(shift) + ); + return value; +} + +inline uint16_t _rotl16(uint16_t value, int shift) +{ + __asm__ __volatile__ ("rolw %%cl, %0" + : "=r"(value) + : "0"(value), "c"(shift) + ); + return value; +} + +inline uint32_t _rotl32(uint32_t value, int shift) +{ + __asm__ __volatile__ ("roll %%cl, %0" + : "=r"(value) + : "0"(value), "c"(shift) + ); + return value; +} + +inline uint64_t _rotl64(uint64_t value, int shift) +{ + return (value << shift) | (value >> (sizeof(value) * 8 - shift)); +} + +inline uint8_t _rotr8(uint8_t value, int shift) +{ + __asm__ __volatile__ ("rorb %%cl, %0" + : "=r"(value) + : "0"(value), "c"(shift) + ); + return value; +} + +inline uint16_t _rotr16(uint16_t value, int shift) +{ + __asm__ __volatile__ ("rorw %%cl, %0" + : "=r"(value) + : "0"(value), "c"(shift) + ); + return value; +} + +inline uint32_t _rotr32(uint32_t value, int shift) +{ + __asm__ __volatile__ ("rorl %%cl, %0" + : "=r"(value) + : "0"(value), "c"(shift) + ); + return value; +} + +inline uint64_t _rotr64(uint64_t value, int shift) +{ + return (value >> shift) | (value << (sizeof(value) * 8 - shift)); +} + +inline uint64_t __rdtsc() +{ + uint32_t hi, lo; + __asm__ __volatile__ ("rdtsc" + : "=a"(lo), "=d"(hi) + ); + return static_cast<uint64_t>(lo) | static_cast<uint64_t>(hi) << 32; +} + + +inline void __cpuid(int regs[4], uint32_t value) +{ + __asm__ __volatile__ ("cpuid" + : "=a"(regs[0]), "=b"(regs[1]), "=c"(regs[2]), "=d"(regs[3]) + : "a"(value) + ); +} + +inline void __movsb(void *d, const void *s, size_t n) { + asm volatile ("rep movsb" + : "=D" (d), + "=S" (s), + "=c" (n) + : "0" (d), + "1" (s), + "2" (n) + : "memory"); +} + +#ifdef __APPLE__ +inline uint16_t __builtin_bswap16(uint16_t value) +{ + __asm__ __volatile__ ("rorw $8, %0" + : "+r"(value) + ); + return value; +} +#endif + +#else +#define _rotl32 _lrotl +#define _rotr32 _lrotr +#define __builtin_bswap16 _byteswap_ushort +#define __builtin_bswap32 _byteswap_ulong +#define __builtin_bswap64 _byteswap_uint64 +inline unsigned long __builtin_ctz(unsigned int x) { unsigned long r; _BitScanForward(&r, x); return r; } + +#if defined(WIN_DRIVER) && (WDK_NTDDI_VERSION <= NTDDI_WIN7) +#ifndef WIN64 +#ifdef __cplusplus +extern "C" { +#endif +VOID +__movsb( + __out_ecount_full(Count) PUCHAR Destination, + __in_ecount(Count) UCHAR const *Source, + __in SIZE_T Count +); +#ifdef __cplusplus +} +#endif +#endif +#endif + +#endif + +inline uint64_t ByteToInt64(uint8_t value) +{ + return static_cast<int64_t>(static_cast<int8_t>(value)); +} + +inline uint64_t WordToInt64(uint16_t value) +{ + return static_cast<int64_t>(static_cast<int16_t>(value)); +} + +inline uint64_t DWordToInt64(uint32_t value) +{ + return static_cast<int64_t>(static_cast<int32_t>(value)); +} + +struct RC5Key { + uint8_t Value[8]; +#ifndef RUNTIME + uint32_t P; + uint32_t Q; +#endif + RC5Key() {} //-V730 +#ifdef RUNTIME + RC5Key(const uint8_t *key) + { + memcpy(Value, key, sizeof(Value)); + } +#endif + void Create(); +}; + +class CipherRC5 +{ +public: + CipherRC5(const RC5Key &key); + void Encrypt(uint8_t *buff, size_t count) const; + void Decrypt(const uint8_t *in, uint8_t *out, size_t count) const; + void Encrypt(const uint32_t *in, uint32_t *out) const; + void Decrypt(const uint32_t *in, uint32_t *out) const; +private: + enum { + w = 32, // u32 size in bits + r = 15, // number of rounds + b = 8, // number of bytes in key + c = 8 * b / w, // 16 - number u32s in key = ceil(8*b/w) + t = 2 * (r + 1), // 34 - size of table S = 2*(r+1) u32s + }; + uint32_t S[t]; // expanded key table +#ifdef RUNTIME + enum { + P = FACE_RC5_P, + Q = FACE_RC5_Q + }; +#else + uint32_t P; + uint32_t Q; +#endif +}; + +class CryptoContainer; + +typedef unsigned short BignumInt; +typedef unsigned long BignumDblInt; +typedef BignumInt *Bignum; + +class BigNumber +{ +public: + BigNumber(); + BigNumber(const BigNumber &src); + BigNumber(const uint8_t *data, size_t size, bool inverse_order = false); + ~BigNumber(); + BigNumber modpow(const BigNumber &exp, const BigNumber &mod) const; + CryptoContainer *modpow(const CryptoContainer &source, size_t exp_offset, size_t exp_size, size_t mod_offset, size_t mod_size) const; + size_t size() const; + bool operator < (const BigNumber &b) const; + uint8_t operator [] (size_t index) const; + BignumInt data(size_t index) const { return bignum_get_word(data_ + index); } +private: + + // no assignment op + BigNumber &operator =(const BigNumber &); + + BigNumber(Bignum data, const BignumInt *salt); + BignumInt bignum_get_word(Bignum b) const; + void bignum_set_word(Bignum b, BignumInt value) const; + void init(size_t length); + void internal_mul(BignumInt *a, BignumInt *b, BignumInt *c, int len) const; + void internal_add_shifted(BignumInt *number, unsigned n, int shift) const; + void internal_mod(BignumInt *a, int alen, BignumInt *m, int mlen, BignumInt *quot, int qshift) const; + uint8_t bignum_byte(Bignum bn, size_t i) const; + int bignum_cmp(const BigNumber &b) const; + enum { + BIGNUM_INT_MASK = 0xFFFFU, + BIGNUM_TOP_BIT = 0x8000U, + BIGNUM_INT_BITS = 16, + BIGNUM_INT_BYTES = (BIGNUM_INT_BITS / 8) + }; + + Bignum data_; +#ifdef RUNTIME + BignumInt salt_[20 / BIGNUM_INT_BYTES]; +#endif +}; + +enum { + ATL_BASE64_FLAG_NONE = 0, + ATL_BASE64_FLAG_NOPAD, + ATL_BASE64_FLAG_NOCRLF +}; +bool Base64Encode(const uint8_t *src, size_t src_len, char *dst, size_t &dst_len); +bool Base64Decode(const char *src, size_t src_len, uint8_t *dst, size_t &dst_len); +size_t Base64EncodeGetRequiredLength(size_t src_len); + +class CryptoContainer +{ +public: + CryptoContainer(uint8_t *data, size_t size, const RC5Key &key); + CryptoContainer(size_t size, const RC5Key &key); + CryptoContainer(const BigNumber &bn); + ~CryptoContainer(); + const uint8_t *data() const { return reinterpret_cast<const uint8_t *>(data_); } + size_t size() const { return size_; } + uint32_t GetDWord(size_t pos) const; + uint16_t GetWord(size_t pos) const; + uint8_t GetByte(size_t pos) const; + uint64_t GetQWord(size_t pos) const; + bool SetDWord(size_t pos, uint32_t value) const; + bool SetWord(size_t pos, uint16_t value) const; + bool SetByte(size_t pos, uint8_t value) const; + void UTF8ToUnicode(size_t offset, size_t len, VMP_WCHAR *dest, size_t dest_size) const; +private: + #define RC5_BLOCK_SIZE 8 + bool EncryptValue(size_t pos, uint8_t *value, size_t value_size) const; + bool DecryptValue(size_t pos, uint8_t *value, size_t value_size) const; + bool is_own_data_; + uint32_t *data_; + size_t size_; + CipherRC5 *cipher_; + + // no copy ctr or assignment op + CryptoContainer(const CryptoContainer &); + CryptoContainer &operator =(const CryptoContainer &); +}; + +class SHA1 +{ +public: + SHA1(); + void Reset(); + void Input(const uint8_t *data, size_t size); + void Input(const CryptoContainer &data, size_t offset, size_t size); + const uint8_t *Result(); + size_t ResultSize() const { return sizeof(digest_); } + bool operator ==(SHA1 &other) { return memcmp(Result(), other.Result(), ResultSize()) == 0; } +private: + void ProcessMessageBlock(); + void PadMessage(); + bool computed_; + size_t message_block_index_; + uint8_t message_block_[64]; + uint32_t length_high_; + uint32_t length_low_; + uint32_t hash_[5]; + uint32_t digest_[5]; +}; + +static uint32_t crc32_table[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +#ifdef RUNTIME +#ifdef VMP_GNU +EXPORT_API uint32_t WINAPI CalcCRC(const void * key, size_t len) __asm__ ("CalcCRC"); +#else +EXPORT_API uint32_t WINAPI CalcCRC(const void * key, size_t len); +#endif +#else +uint32_t CalcCRC(const void * key, size_t len); +#endif + +class CRCValueCryptor +{ +public: +#ifdef RUNTIME + FORCE_INLINE CRCValueCryptor() : key_(FACE_CRC_INFO_SALT) {} + FORCE_INLINE uint32_t Decrypt(uint32_t value) + { + uint32_t res = value ^ key_; + key_ = _rotl32(key_, 7) ^ res; + return res; + } +#else + CRCValueCryptor(uint32_t key) : key_(key) {} + uint32_t Encrypt(uint32_t value) + { + uint32_t old_key = key_; + key_ = _rotl32(key_, 7) ^ value; + return value ^ old_key; + } +#endif +private: + uint32_t key_; +}; + +#endif
\ No newline at end of file diff --git a/runtime/file_manager.cc b/runtime/file_manager.cc new file mode 100644 index 0000000..9dcfc29 --- /dev/null +++ b/runtime/file_manager.cc @@ -0,0 +1,1189 @@ +#ifdef WIN_DRIVER +#else +#include "common.h" +#include "objects.h" + +#include "crypto.h" +#include "core.h" +#include "file_manager.h" +#include "hook_manager.h" +#include "utils.h" +#include "registry_manager.h" + +/** + * hooked functions + */ + +NTSTATUS WINAPI HookedNtQueryAttributesFile(POBJECT_ATTRIBUTES ObjectAttributes, PFILE_BASIC_INFORMATION FileInformation) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtQueryAttributesFile(ObjectAttributes, FileInformation); +} + +NTSTATUS WINAPI HookedNtCreateFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtCreateFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, AllocationSize, FileAttributes, ShareAccess, CreateDisposition, CreateOptions, EaBuffer, EaLength); +} + +NTSTATUS WINAPI HookedNtOpenFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess, ULONG OpenOptions) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtOpenFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, ShareAccess, OpenOptions); +} + +NTSTATUS WINAPI HookedNtQueryInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtQueryInformationFile(FileHandle, IoStatusBlock, FileInformation, Length, FileInformationClass); +} + +NTSTATUS WINAPI HookedNtQueryVolumeInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, ULONG Length, FS_INFORMATION_CLASS FsInformationClass) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtQueryVolumeInformationFile(FileHandle, IoStatusBlock, FsInformation, Length, FsInformationClass); +} + +NTSTATUS WINAPI HookedNtSetInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtSetInformationFile(FileHandle, IoStatusBlock, FileInformation, Length, FileInformationClass); +} + +NTSTATUS WINAPI HookedNtQueryDirectoryFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, + ULONG Length, FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry, PUNICODE_STRING FileName, BOOLEAN RestartScan) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtQueryDirectoryFile(FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, FileInformation, Length, FileInformationClass, ReturnSingleEntry, FileName, RestartScan); +} + +NTSTATUS WINAPI HookedNtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtReadFile(FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, Buffer, Length, ByteOffset, Key); +} + +NTSTATUS WINAPI HookedNtCreateSection(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PLARGE_INTEGER MaximumSize, ULONG SectionPageProtection, ULONG AllocationAttributes, HANDLE FileHandle) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtCreateSection(SectionHandle, DesiredAccess, ObjectAttributes, MaximumSize, SectionPageProtection, AllocationAttributes, FileHandle); +} + +NTSTATUS WINAPI HookedNtQuerySection(HANDLE SectionHandle, SECTION_INFORMATION_CLASS InformationClass, PVOID InformationBuffer, ULONG InformationBufferSize, PULONG ResultLength) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtQuerySection(SectionHandle, InformationClass, InformationBuffer, InformationBufferSize, ResultLength); +} + +NTSTATUS WINAPI HookedNtMapViewOfSection(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, SECTION_INHERIT InheritDisposition, ULONG AllocationType, ULONG Win32Protect) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtMapViewOfSection(SectionHandle, ProcessHandle, BaseAddress, ZeroBits, CommitSize, SectionOffset, ViewSize, InheritDisposition, AllocationType, Win32Protect); +} + +NTSTATUS WINAPI HookedNtUnmapViewOfSection(HANDLE ProcessHandle, PVOID BaseAddress) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtUnmapViewOfSection(ProcessHandle, BaseAddress); +} + +NTSTATUS WINAPI HookedNtQueryVirtualMemory(HANDLE ProcessHandle, PVOID BaseAddress, MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID Buffer, ULONG Length, PULONG ResultLength) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtQueryVirtualMemory(ProcessHandle, BaseAddress, MemoryInformationClass, Buffer, Length, ResultLength); +} + +/** + * FileManager + */ + +FileManager::FileManager(const uint8_t *data, HMODULE instance, const uint8_t *key, VirtualObjectList *objects) + : instance_(instance) + , data_(data) + , objects_(objects) + , nt_query_attributes_file_(NULL) + , nt_create_file_(NULL) + , nt_open_file_(NULL) + , nt_read_file_(NULL) + , nt_query_information_file_(NULL) + , nt_query_volume_information_file_(NULL) + , nt_set_information_file_(NULL) + , nt_query_directory_file_(NULL) + , nt_close_(NULL) + , nt_create_section_(NULL) + , nt_query_section_(NULL) + , nt_map_view_of_section_(NULL) + , nt_unmap_view_of_section_(NULL) + , nt_query_virtual_memory_(NULL) +{ + wchar_t dos_path[MAX_PATH]; + wchar_t nt_path[MAX_PATH]; + + key_ = *(reinterpret_cast<const uint32_t *>(key)); + + if (GetModuleFileNameW(NULL, dos_path, _countof(dos_path))) { + wchar_t *name = wcsrchr(dos_path, L'\\'); + name = (name ? name + 1 : dos_path); + *name = 0; + } else { + dos_path[0] = 0; + } + + nt_path[0] = 0; + HANDLE dir = CreateFileW(dos_path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); + if (dir != INVALID_HANDLE_VALUE) { + typedef NTSTATUS (WINAPI tNtQueryObject)(HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength); + HMODULE dll = GetModuleHandleA(VMProtectDecryptStringA("ntdll.dll")); + tNtQueryObject *nt_query_object = static_cast<tNtQueryObject *>(InternalGetProcAddress(dll, VMProtectDecryptStringA("NtQueryObject"))); + if (nt_query_object) { + DWORD size = 0x800; + OBJECT_NAME_INFORMATION *info = reinterpret_cast<OBJECT_NAME_INFORMATION *>(new uint8_t[size]); + if (NT_SUCCESS(nt_query_object(dir, ObjectNameInformation, info, size, NULL))) { + memcpy(nt_path, info->Name.Buffer, info->Name.Length); + size = info->Name.Length / sizeof(wchar_t); + nt_path[size] = '\\'; + nt_path[size + 1] = 0; + } + delete [] info; + } + CloseHandle(dir); + } + + wchar_t *dos_end = dos_path + wcslen(dos_path); + wchar_t *nt_end = nt_path + wcslen(nt_path); + while (dos_end > dos_path && nt_end > nt_path) { + if (_wcsnicmp(dos_end, nt_end, 1) != 0) + break; + dos_end--; + nt_end--; + } + dos_end++; + nt_end++; + if (*dos_end == '\\') { + dos_end++; + nt_end++; + } + dos_root_.append(dos_path, dos_end - dos_path); + nt_root_.append(nt_path, nt_end - nt_path); + + Path path(dos_end); + const OBJECT_DIRECTORY *directory_enc = reinterpret_cast<const OBJECT_DIRECTORY *>(data_); + const OBJECT_ENTRY *entry_enc = reinterpret_cast<const OBJECT_ENTRY *>(directory_enc + 1); + OBJECT_DIRECTORY directory = DecryptDirectory(directory_enc); + for (size_t i = 0; i < directory.NumberOfEntries; i++) { + OBJECT_ENTRY entry = DecryptEntry(&entry_enc[i]); + if (DecryptString(reinterpret_cast<LPCWSTR>(reinterpret_cast<uint8_t *>(instance_) + entry.NameOffset), dos_path, _countof(dos_path))) { + file_name_list_.push_back(path.Combine(dos_path)); + } else { + file_name_list_.push_back(UnicodeString()); + } + } +} + +void FileManager::HookAPIs(HookManager &hook_manager) +{ + hook_manager.Begin(); + HMODULE dll = GetModuleHandleA(VMProtectDecryptStringA("ntdll.dll")); + nt_query_attributes_file_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtQueryAttributesFile"), &HookedNtQueryAttributesFile); + nt_create_file_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtCreateFile"), &HookedNtCreateFile); + nt_open_file_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtOpenFile"), &HookedNtOpenFile); + nt_read_file_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtReadFile"), &HookedNtReadFile); + nt_query_information_file_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtQueryInformationFile"), &HookedNtQueryInformationFile); + nt_query_volume_information_file_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtQueryVolumeInformationFile"), &HookedNtQueryVolumeInformationFile); + nt_set_information_file_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtSetInformationFile"), &HookedNtSetInformationFile); + nt_query_directory_file_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtQueryDirectoryFile"), &HookedNtQueryDirectoryFile); + nt_create_section_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtCreateSection"), &HookedNtCreateSection); + nt_query_section_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtQuerySection"), &HookedNtQuerySection); + nt_map_view_of_section_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtMapViewOfSection"), &HookedNtMapViewOfSection); + nt_unmap_view_of_section_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtUnmapViewOfSection"), &HookedNtUnmapViewOfSection); + nt_query_virtual_memory_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtQueryVirtualMemory"), &HookedNtQueryVirtualMemory); + hook_manager.End(); +} + +void FileManager::UnhookAPIs(HookManager &hook_manager) +{ + hook_manager.Begin(); + hook_manager.UnhookAPI(nt_query_attributes_file_); + hook_manager.UnhookAPI(nt_create_file_); + hook_manager.UnhookAPI(nt_open_file_); + hook_manager.UnhookAPI(nt_read_file_); + hook_manager.UnhookAPI(nt_query_information_file_); + hook_manager.UnhookAPI(nt_query_volume_information_file_); + hook_manager.UnhookAPI(nt_set_information_file_); + hook_manager.UnhookAPI(nt_query_directory_file_); + hook_manager.UnhookAPI(nt_create_section_); + hook_manager.UnhookAPI(nt_query_section_); + hook_manager.UnhookAPI(nt_map_view_of_section_); + hook_manager.UnhookAPI(nt_unmap_view_of_section_); + hook_manager.UnhookAPI(nt_query_virtual_memory_); + hook_manager.End(); +} + +bool FileManager::DecryptString(LPCWSTR str_enc, LPWSTR str, size_t count) const +{ + for (size_t i = 0; i < count; i++) { + str[i] = static_cast<wchar_t>(str_enc[i] ^ (_rotl32(key_, static_cast<int>(i)) + i)); + if (!str[i]) + return true; + } + // source string is too long + return false; +} + +bool FileManager::OpenFiles(RegistryManager ®istry_manager) +{ + const OBJECT_DIRECTORY *directory_enc = reinterpret_cast<const OBJECT_DIRECTORY *>(data_); + const OBJECT_ENTRY *entry_enc = reinterpret_cast<const OBJECT_ENTRY *>(directory_enc + 1); + + wchar_t file_name[MAX_PATH]; + OBJECT_DIRECTORY directory = DecryptDirectory(directory_enc); + for (size_t i = 0; i < directory.NumberOfEntries; i++) { + OBJECT_ENTRY entry = DecryptEntry(&entry_enc[i]); + if ((entry.Options & (FILE_LOAD | FILE_REGISTER | FILE_INSTALL)) == 0) + continue; + + if (!DecryptString(reinterpret_cast<LPCWSTR>(reinterpret_cast<uint8_t *>(instance_) + entry.NameOffset), file_name, _countof(file_name))) + return false; + + HMODULE h = LoadLibraryW(file_name); + if (h) { + for (size_t j = 0; j < 2; j++) { + size_t mask = (j == 0) ? FILE_REGISTER : FILE_INSTALL; + if (entry.Options & mask) { + VMP_CHAR error[MAX_PATH + 100]; + error[0] = 0; + void *proc = InternalGetProcAddress(h, (j == 0) ? "DllRegisterServer" : "DllInstall"); + if (proc) { + HRESULT res = S_OK; + registry_manager.BeginRegisterServer(); + try { + if (j == 0) { + typedef HRESULT (WINAPI tRegisterServer)(void); + tRegisterServer *register_server = reinterpret_cast<tRegisterServer *>(proc); + res = register_server(); + } else { + typedef HRESULT (WINAPI tInstallServer)(BOOL, LPCWSTR); + tInstallServer *install_server = reinterpret_cast<tInstallServer *>(proc); + res = install_server(TRUE, L""); + } + } catch(...) { + res = 0xC0000005; + } + registry_manager.EndRegisterServer(); + if (res != S_OK) + swprintf_s(error, L"Cannot %s server %s\nError: 0x%X", (j == 0) ? L"register" : L"install", file_name, res); + } else { + swprintf_s(error, L"The procedure entry point %s could not be located in the module %s", (j == 0) ? L"DllRegisterServer" : L"DllInstall", file_name); + } + if (error[0]) { + FreeLibrary(h); + ShowMessage(error); + return false; + } + } + } + if ((entry.Options & FILE_LOAD) == 0) + FreeLibrary(h); + } else { + VMP_CHAR error[MAX_PATH + 100]; + swprintf_s(error, L"Cannot load file %s\nError: %d", file_name, GetLastError()); + ShowMessage(error); + return false; + } + } + return true; +} + +NTSTATUS __forceinline FileManager::TrueNtQueryAttributesFile(POBJECT_ATTRIBUTES ObjectAttributes, PFILE_BASIC_INFORMATION FileInformation) +{ + typedef NTSTATUS (WINAPI tNtQueryAttributesFile)(POBJECT_ATTRIBUTES ObjectAttributes, PFILE_BASIC_INFORMATION FileInformation); + return reinterpret_cast<tNtQueryAttributesFile *>(nt_query_attributes_file_)(ObjectAttributes, FileInformation); +} + +NTSTATUS __forceinline FileManager::TrueNtCreateFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength) +{ + typedef NTSTATUS (WINAPI tNtCreateFile)(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength); + return reinterpret_cast<tNtCreateFile *>(nt_create_file_)(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, AllocationSize, FileAttributes, ShareAccess, CreateDisposition, CreateOptions, EaBuffer, EaLength); +} + +NTSTATUS __forceinline FileManager::TrueNtOpenFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess, ULONG OpenOptions) +{ + typedef NTSTATUS (WINAPI tNtOpenFile)(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess, ULONG OpenOptions); + return reinterpret_cast<tNtOpenFile *>(nt_open_file_)(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, ShareAccess, OpenOptions); +} + +NTSTATUS __forceinline FileManager::TrueNtQueryInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass) +{ + typedef NTSTATUS (WINAPI tNtQueryInformationFile)(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); + return reinterpret_cast<tNtQueryInformationFile *>(nt_query_information_file_)(FileHandle, IoStatusBlock, FileInformation, Length, FileInformationClass); +} + +NTSTATUS __forceinline FileManager::TrueNtQueryVolumeInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, ULONG Length, FS_INFORMATION_CLASS FsInformationClass) +{ + typedef NTSTATUS (WINAPI tNtQueryVolumeInformationFile)(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, ULONG Length, FS_INFORMATION_CLASS FsInformationClass); + return reinterpret_cast<tNtQueryVolumeInformationFile *>(nt_query_volume_information_file_)(FileHandle, IoStatusBlock, FsInformation, Length, FsInformationClass); +} + +NTSTATUS __forceinline FileManager::TrueNtSetInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass) +{ + typedef NTSTATUS (WINAPI tNtSetInformationFile)(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); + return reinterpret_cast<tNtSetInformationFile *>(nt_set_information_file_)(FileHandle, IoStatusBlock, FileInformation, Length, FileInformationClass); +} + +NTSTATUS __forceinline FileManager::TrueNtQueryDirectoryFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry, PUNICODE_STRING FileName, BOOLEAN RestartScan) +{ + typedef NTSTATUS(WINAPI tNtQueryDirectoryFile)(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry, PUNICODE_STRING FileName, BOOLEAN RestartScan); + return reinterpret_cast<tNtQueryDirectoryFile *>(nt_query_directory_file_)(FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, FileInformation, Length, FileInformationClass, ReturnSingleEntry, FileName, RestartScan); +} + +NTSTATUS __forceinline FileManager::TrueNtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key) +{ + typedef NTSTATUS (WINAPI tNtReadFile)(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key); + return reinterpret_cast<tNtReadFile *>(nt_read_file_)(FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, Buffer, Length, ByteOffset, Key); +} + +NTSTATUS __forceinline FileManager::TrueNtCreateSection(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PLARGE_INTEGER MaximumSize, ULONG SectionPageProtection, ULONG AllocationAttributes, HANDLE FileHandle) +{ + typedef NTSTATUS (WINAPI tNtCreateSection)(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PLARGE_INTEGER MaximumSize, ULONG SectionPageProtection, ULONG AllocationAttributes, HANDLE FileHandle); + return reinterpret_cast<tNtCreateSection *>(nt_create_section_)(SectionHandle, DesiredAccess, ObjectAttributes, MaximumSize, SectionPageProtection, AllocationAttributes, FileHandle); +} + +NTSTATUS __forceinline FileManager::TrueNtQuerySection(HANDLE SectionHandle, SECTION_INFORMATION_CLASS InformationClass, PVOID InformationBuffer, ULONG InformationBufferSize, PULONG ResultLength) +{ + typedef NTSTATUS (WINAPI tNtQuerySection)(HANDLE SectionHandle, SECTION_INFORMATION_CLASS InformationClass, PVOID InformationBuffer, ULONG InformationBufferSize, PULONG ResultLength); + return reinterpret_cast<tNtQuerySection *>(nt_query_section_)(SectionHandle, InformationClass, InformationBuffer, InformationBufferSize, ResultLength); +} + +NTSTATUS __forceinline FileManager::TrueNtMapViewOfSection(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, SECTION_INHERIT InheritDisposition, ULONG AllocationType, ULONG Win32Protect) +{ + typedef NTSTATUS (WINAPI tNtMapViewOfSection)(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, SECTION_INHERIT InheritDisposition, ULONG AllocationType, ULONG Win32Protect); + return reinterpret_cast<tNtMapViewOfSection *>(nt_map_view_of_section_)(SectionHandle, ProcessHandle, BaseAddress, ZeroBits, CommitSize, SectionOffset, ViewSize, InheritDisposition, AllocationType, Win32Protect); +} + +NTSTATUS __forceinline FileManager::TrueNtUnmapViewOfSection(HANDLE ProcessHandle, PVOID BaseAddress) +{ + typedef NTSTATUS (WINAPI tNtUnmapViewOfSection)(HANDLE ProcessHandle, PVOID BaseAddress); + return reinterpret_cast<tNtUnmapViewOfSection *>(nt_unmap_view_of_section_)(ProcessHandle, BaseAddress); +} + +NTSTATUS __forceinline FileManager::TrueNtQueryVirtualMemory(HANDLE ProcessHandle, PVOID BaseAddress, MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID Buffer, ULONG Length, PULONG ResultLength) +{ + typedef NTSTATUS (WINAPI tNtQueryVirtualMemory)(HANDLE ProcessHandle, PVOID BaseAddress, MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID Buffer, ULONG Length, PULONG ResultLength); + return reinterpret_cast<tNtQueryVirtualMemory *>(nt_query_virtual_memory_)(ProcessHandle, BaseAddress, MemoryInformationClass, Buffer, Length, ResultLength); +} + +OBJECT_DIRECTORY FileManager::DecryptDirectory(const OBJECT_DIRECTORY *directory_enc) const +{ + OBJECT_DIRECTORY res; + res.NumberOfEntries = directory_enc->NumberOfEntries ^ key_; + return res; +} + +OBJECT_ENTRY FileManager::DecryptEntry(const OBJECT_ENTRY *entry_enc) const +{ + OBJECT_ENTRY res; + res.NameOffset = entry_enc->NameOffset ^ key_; + res.OffsetToData = entry_enc->OffsetToData ^ key_; + res.Size = entry_enc->Size ^ key_; + res.Options = entry_enc->Options ^ key_; + return res; +} + +NTSTATUS __forceinline FileManager::TrueNtQueryObject(HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength) +{ + return Core::Instance()->TrueNtQueryObject(Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength, ReturnLength); +} + +const OBJECT_ENTRY *FileManager::FindEntry(HANDLE directory, PUNICODE_STRING object_name) +{ + UnicodeString file_name; + bool check_root = true; + if (directory) { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetFile(directory); + if (object) { + check_root = false; + const OBJECT_DIRECTORY *directory_enc = reinterpret_cast<const OBJECT_DIRECTORY *>(data_); + for (size_t i = 0; i < file_name_list_.size(); i++) { + if (object->ref() == reinterpret_cast<const OBJECT_ENTRY *>(directory_enc + 1) + i) { + file_name = file_name_list_[i].c_str(); + break; + } + } + } else { + DWORD size = 0x800; + OBJECT_NAME_INFORMATION *info = reinterpret_cast<OBJECT_NAME_INFORMATION *>(new uint8_t[size]); + if (NT_SUCCESS(TrueNtQueryObject(directory, ObjectNameInformation, info, size, NULL))) + file_name.append(info->Name.Buffer, info->Name.Length / sizeof(wchar_t)); + delete[] info; + } + if (file_name.size()) + file_name.append(L"\\"); + } + file_name.append(object_name->Buffer, object_name->Length / sizeof(wchar_t)); + + LPCWSTR name = file_name.c_str(); + if (check_root) { + LPCWSTR path; + if (name[0] == '\\' && name[1] == '?' && name[2] == '?' && name[3] == '\\') { + path = dos_root_.c_str(); + name += 4; + if (name[0] == 'U' && name[1] == 'N' && name[2] == 'C' && name[3] == '\\') { + name += 3; + if (path[0] == '\\' && path[1] == '\\') + path++; + } + } + else { + path = nt_root_.c_str(); + } + + size_t len = wcslen(path); + if (_wcsnicmp(name, path, len) != 0) + return NULL; + name += len; + } + + const OBJECT_DIRECTORY *directory_enc = reinterpret_cast<const OBJECT_DIRECTORY *>(data_); + for (size_t i = 0; i < file_name_list_.size(); i++) { + UnicodeString *file_name = &file_name_list_[i]; + size_t len = file_name->size(); + if (_wcsnicmp(file_name->c_str(), name, len) == 0) { + const OBJECT_ENTRY *entry_enc = reinterpret_cast<const OBJECT_ENTRY *>(directory_enc + 1) + i; + if (name[len]) { + OBJECT_ENTRY entry = DecryptEntry(entry_enc); + if (entry.OffsetToData || name[len] != '\\' || name[len + 1]) + continue; + } + return entry_enc; + } + } + + return NULL; +} + +__declspec(noinline) bool FileManager::ReadFile(const OBJECT_ENTRY *entry, uint64_t offset, void *dst, size_t size) const +{ + if (entry->Size < offset + size) + return false; + + uint8_t *source = reinterpret_cast<uint8_t *>(instance_) + entry->OffsetToData; + uint8_t *address = reinterpret_cast<uint8_t *>(dst); + for (size_t p = 0; p < size; p++) { + uint64_t i = offset + p; + address[p] = source[i] ^ static_cast<uint8_t>(_rotl32(key_, static_cast<int>(i)) + i); + } + return true; +} + +NTSTATUS FileManager::ReadImageHeader(const OBJECT_ENTRY *entry, IMAGE_NT_HEADERS *header) const +{ + IMAGE_DOS_HEADER dos_header; + if (ReadFile(entry, 0, &dos_header, sizeof(dos_header)) && dos_header.e_magic == IMAGE_DOS_SIGNATURE && dos_header.e_lfanew) { + IMAGE_NT_HEADERS nt_header; + if (ReadFile(entry, dos_header.e_lfanew, &nt_header, sizeof(nt_header))) { + if (nt_header.Signature == IMAGE_NT_SIGNATURE && (nt_header.FileHeader.Characteristics & IMAGE_FILE_DLL) != 0) { +#ifdef _WIN64 + if (nt_header.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC && nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64) +#else + if (nt_header.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC && (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I386 || nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I486 || nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I586)) +#endif + *header = nt_header; + return STATUS_SUCCESS; + } + } + } + return STATUS_INVALID_IMAGE_FORMAT; +} + +NTSTATUS FileManager::ReadImage(const OBJECT_ENTRY *entry, void *base) const +{ + IMAGE_NT_HEADERS tmp_header; + NTSTATUS status = ReadImageHeader(entry, &tmp_header); + if (status != STATUS_SUCCESS) + return status; + + uint8_t *image_base = reinterpret_cast<uint8_t *>(base); + if (!ReadFile(entry, 0, image_base, tmp_header.OptionalHeader.SizeOfHeaders)) + return STATUS_INVALID_IMAGE_FORMAT; + + IMAGE_DOS_HEADER *dos_header = reinterpret_cast<IMAGE_DOS_HEADER *>(image_base); + IMAGE_NT_HEADERS *nt_header = reinterpret_cast<IMAGE_NT_HEADERS *>(image_base + dos_header->e_lfanew); + IMAGE_SECTION_HEADER *sections = reinterpret_cast<IMAGE_SECTION_HEADER *>(reinterpret_cast<uint8_t *>(&nt_header->OptionalHeader) + nt_header->FileHeader.SizeOfOptionalHeader); + + // copy sections + for (size_t i = 0; i < nt_header->FileHeader.NumberOfSections; i++) { + IMAGE_SECTION_HEADER *section = sections + i; + + uint32_t virtual_size = section->Misc.VirtualSize; + uint32_t physical_size = section->SizeOfRawData; + + uint8_t *address = image_base + section->VirtualAddress; + ::ZeroMemory(address, virtual_size); + + if (!ReadFile(entry, section->PointerToRawData, address, std::min(physical_size, virtual_size))) + return STATUS_INVALID_IMAGE_FORMAT; + } + + // setup relocs + ptrdiff_t delta_base = image_base - reinterpret_cast<uint8_t *>(nt_header->OptionalHeader.ImageBase); + if (delta_base) { + IMAGE_DATA_DIRECTORY *reloc_directory = &nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; + if (reloc_directory->VirtualAddress && reloc_directory->Size && (nt_header->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) == 0) { + size_t processed = 0; + while (processed < reloc_directory->Size) { + IMAGE_BASE_RELOCATION *reloc = reinterpret_cast<IMAGE_BASE_RELOCATION *>(image_base + reloc_directory->VirtualAddress + processed); + if (!reloc->SizeOfBlock) + break; + + if (reloc->SizeOfBlock <= sizeof(IMAGE_BASE_RELOCATION) || (reloc->SizeOfBlock & 1) != 0) + return STATUS_INVALID_IMAGE_FORMAT; + + size_t c = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) >> 1; + for (size_t i = 0; i < c; i++) { + uint16_t type_offset = reinterpret_cast<uint16_t *>(reloc + 1)[i]; + uint8_t *address = image_base + reloc->VirtualAddress + (type_offset & 0xfff); + switch (type_offset >> 12) { + case IMAGE_REL_BASED_HIGHLOW: + *(reinterpret_cast<uint32_t *>(address)) += static_cast<uint32_t>(delta_base); + break; + case IMAGE_REL_BASED_HIGH: + *(reinterpret_cast<uint16_t *>(address)) += static_cast<uint16_t>(delta_base >> 16); + break; + case IMAGE_REL_BASED_LOW: + *(reinterpret_cast<uint16_t *>(address)) += static_cast<uint16_t>(delta_base); + break; + case IMAGE_REL_BASED_DIR64: + *(reinterpret_cast<uint64_t *>(address)) += delta_base; + break; + } + } + processed += reloc->SizeOfBlock; + } + } + nt_header->OptionalHeader.ImageBase = reinterpret_cast<size_t>(image_base); + } + + // setup pages protection + DWORD old_protect; + if (!VirtualProtect(image_base, nt_header->OptionalHeader.SizeOfHeaders, PAGE_READONLY, &old_protect)) + return STATUS_INVALID_PAGE_PROTECTION; + + for (size_t i = 0; i < nt_header->FileHeader.NumberOfSections; i++) { + IMAGE_SECTION_HEADER *section = sections + i; + + ULONG protection = 0; + if ((section->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) != 0) + protection |= PAGE_NOCACHE; + if ((section->Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) == (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) { + protection |= PAGE_EXECUTE_READWRITE; + } else if ((section->Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ)) == (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ)) { + protection |= PAGE_EXECUTE_READ; + } else if ((section->Characteristics & (IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) == (IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) { + protection |= PAGE_READWRITE; + } else if ((section->Characteristics & IMAGE_SCN_MEM_WRITE) != 0) { + protection |= PAGE_WRITECOPY; + } else if ((section->Characteristics & IMAGE_SCN_MEM_READ) != 0) { + protection |= PAGE_READONLY; + } else { + protection |= PAGE_NOACCESS; + } + if (!VirtualProtect(image_base + section->VirtualAddress, section->Misc.VirtualSize, protection, &old_protect)) + return STATUS_INVALID_PAGE_PROTECTION; + } + return STATUS_SUCCESS; +} + +NTSTATUS FileManager::NtQueryAttributesFile(POBJECT_ATTRIBUTES ObjectAttributes, PFILE_BASIC_INFORMATION FileInformation) +{ + const OBJECT_ENTRY *entry = FindEntry(ObjectAttributes->RootDirectory, ObjectAttributes->ObjectName); + if (entry) { + try { + FileInformation->CreationTime.QuadPart = 0; + FileInformation->LastAccessTime.QuadPart = 0; + FileInformation->LastWriteTime.QuadPart = 0; + FileInformation->ChangeTime.QuadPart = 0; + FileInformation->FileAttributes = FILE_ATTRIBUTE_READONLY; + return STATUS_SUCCESS; + } catch(...) { + return STATUS_ACCESS_VIOLATION; + } + } + + return TrueNtQueryAttributesFile(ObjectAttributes, FileInformation); +} + +NTSTATUS FileManager::NtCreateFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength) +{ + const OBJECT_ENTRY *entry = FindEntry(ObjectAttributes->RootDirectory, ObjectAttributes->ObjectName); + if (entry) { + try { + NTSTATUS status; + switch (CreateDisposition) { + case FILE_OPEN: + case FILE_OPEN_IF: + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->Add(OBJECT_FILE, const_cast<OBJECT_ENTRY *>(entry), ::CreateEventA(NULL, false, false, NULL), DesiredAccess); + *FileHandle = object->handle(); + } + IoStatusBlock->Information = FILE_OPENED; + status = STATUS_SUCCESS; + break; + case FILE_SUPERSEDE: + case FILE_CREATE: + case FILE_OVERWRITE: + case FILE_OVERWRITE_IF: + IoStatusBlock->Information = FILE_EXISTS; + status = STATUS_ACCESS_DENIED; + break; + default: + IoStatusBlock->Information = FILE_EXISTS; + status = STATUS_NOT_IMPLEMENTED; + break; + } + IoStatusBlock->Status = status; + return status; + } catch(...) { + return STATUS_ACCESS_VIOLATION; + } + } + + return TrueNtCreateFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, AllocationSize, FileAttributes, ShareAccess, CreateDisposition, CreateOptions, EaBuffer, EaLength); +} + +NTSTATUS FileManager::NtOpenFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess, ULONG OpenOptions) +{ + const OBJECT_ENTRY *entry = FindEntry(ObjectAttributes->RootDirectory, ObjectAttributes->ObjectName); + if (entry) { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->Add(OBJECT_FILE, const_cast<OBJECT_ENTRY *>(entry), ::CreateEventA(NULL, false, false, NULL), DesiredAccess); + try { + *FileHandle = object->handle(); + NTSTATUS status = STATUS_SUCCESS; + IoStatusBlock->Status = status; + return status; + } catch(...) { + return STATUS_ACCESS_VIOLATION; + } + } + + return TrueNtOpenFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, ShareAccess, OpenOptions); +} + +NTSTATUS FileManager::NtQueryInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass) +{ + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetFile(FileHandle); + if (object) { + OBJECT_ENTRY entry = DecryptEntry(static_cast<const OBJECT_ENTRY*>(object->ref())); + try { + NTSTATUS status; + switch (FileInformationClass) { + case FileBasicInformation: + { + if (Length < sizeof(FILE_BASIC_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + FILE_BASIC_INFORMATION *info = reinterpret_cast<FILE_BASIC_INFORMATION *>(FileInformation); + info->CreationTime.QuadPart = 0; + info->LastAccessTime.QuadPart = 0; + info->LastWriteTime.QuadPart = 0; + info->ChangeTime.QuadPart = 0; + info->FileAttributes = entry.OffsetToData ? FILE_ATTRIBUTE_READONLY : FILE_ATTRIBUTE_DIRECTORY; + } + status = STATUS_SUCCESS; + break; + case FilePositionInformation: + { + if (Length < sizeof(FILE_POSITION_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + FILE_POSITION_INFORMATION *info = reinterpret_cast<FILE_POSITION_INFORMATION *>(FileInformation); + info->CurrentByteOffset.QuadPart = object->file_position(); + } + status = STATUS_SUCCESS; + break; + case FileStandardInformation: + { + if (Length < sizeof(FILE_STANDARD_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + FILE_STANDARD_INFORMATION *info = reinterpret_cast<FILE_STANDARD_INFORMATION *>(FileInformation); + info->AllocationSize.QuadPart = 0; + info->EndOfFile.QuadPart = entry.Size; + info->NumberOfLinks = 0; + info->DeletePending = FALSE; + info->Directory = entry.OffsetToData ? FALSE : TRUE; + } + status = STATUS_SUCCESS; + break; + case FileAllInformation: + { + if (Length < sizeof(FILE_ALL_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + FILE_ALL_INFORMATION *info = reinterpret_cast<FILE_ALL_INFORMATION *>(FileInformation); + info->BasicInformation.CreationTime.QuadPart = 0; + info->BasicInformation.LastAccessTime.QuadPart = 0; + info->BasicInformation.LastWriteTime.QuadPart = 0; + info->BasicInformation.ChangeTime.QuadPart = 0; + info->BasicInformation.FileAttributes = entry.OffsetToData ? FILE_ATTRIBUTE_READONLY : FILE_ATTRIBUTE_DIRECTORY; + info->StandardInformation.AllocationSize.QuadPart = 0; + info->StandardInformation.EndOfFile.QuadPart = entry.Size; + info->StandardInformation.NumberOfLinks = 0; + info->StandardInformation.DeletePending = FALSE; + info->StandardInformation.Directory = entry.OffsetToData ? FALSE : TRUE; + info->InternalInformation.IndexNumber.QuadPart = 0; + info->EaInformation.EaSize = 0; + info->AccessInformation.AccessFlags = object->access(); + info->PositionInformation.CurrentByteOffset.QuadPart = object->file_position(); + info->ModeInformation.Mode = 0; + info->AlignmentInformation.AlignmentRequirement = 0; + info->NameInformation.FileNameLength = 0; + info->NameInformation.FileName[0] = 0; + } + status = STATUS_SUCCESS; + break; + default: + status = STATUS_NOT_IMPLEMENTED; + break; + } + IoStatusBlock->Status = status; + return status; + } catch(...) { + return STATUS_ACCESS_VIOLATION; + } + } + } + + return TrueNtQueryInformationFile(FileHandle, IoStatusBlock, FileInformation, Length, FileInformationClass); +} + +NTSTATUS FileManager::NtQueryVolumeInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, ULONG Length, FS_INFORMATION_CLASS FsInformationClass) +{ + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetFile(FileHandle); + if (object) { + try { + NTSTATUS status = STATUS_SUCCESS; + switch (FsInformationClass) { + case FileFsVolumeInformation: + { + if (Length < sizeof(FILE_FS_VOLUME_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + FILE_FS_VOLUME_INFORMATION *info = reinterpret_cast<FILE_FS_VOLUME_INFORMATION *>(FsInformation); + info->VolumeCreationTime.QuadPart = 0; + info->VolumeSerialNumber = 0; + info->VolumeLabelLength = 0; + info->SupportsObjects = FALSE; + info->VolumeLabel[0] = 0; + } + break; + case FileFsDeviceInformation: + { + if (Length < sizeof(FILE_FS_DEVICE_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + FILE_FS_DEVICE_INFORMATION *info = reinterpret_cast<FILE_FS_DEVICE_INFORMATION *>(FsInformation); + info->DeviceType = FILE_DEVICE_DISK; + info->Characteristics = 0; + } + break; + case FileFsAttributeInformation: + { + if (Length < sizeof(FILE_FS_ATTRIBUTE_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + FILE_FS_ATTRIBUTE_INFORMATION *info = reinterpret_cast<FILE_FS_ATTRIBUTE_INFORMATION *>(FsInformation); + info->FileSystemAttributes = FILE_READ_ONLY_VOLUME; + info->MaximumComponentNameLength = MAX_PATH; + info->FileSystemNameLength = 0; + info->FileSystemName[0] = 0; + } + break; + default: + status = STATUS_NOT_IMPLEMENTED; + break; + } + IoStatusBlock->Status = status; + return status; + } catch(...) { + return STATUS_ACCESS_VIOLATION; + } + } + } + + return TrueNtQueryVolumeInformationFile(FileHandle, IoStatusBlock, FsInformation, Length, FsInformationClass); +} + +NTSTATUS FileManager::NtSetInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass) +{ + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetFile(FileHandle); + if (object) { + try { + NTSTATUS status; + switch (FileInformationClass) { + case FilePositionInformation: + { + if (Length < sizeof(FILE_POSITION_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + FILE_POSITION_INFORMATION *info = reinterpret_cast<FILE_POSITION_INFORMATION *>(FileInformation); + if (info->CurrentByteOffset.HighPart) + info->CurrentByteOffset.LowPart = -1; + object->set_file_position(info->CurrentByteOffset.LowPart); + + status = STATUS_SUCCESS; + break; + } + default: + status = STATUS_NOT_IMPLEMENTED; + break; + } + IoStatusBlock->Status = status; + return status; + } catch(...) { + return STATUS_ACCESS_VIOLATION; + } + } + } + + return TrueNtSetInformationFile(FileHandle, IoStatusBlock, FileInformation, Length, FileInformationClass); +} + +NTSTATUS FileManager::NtQueryDirectoryFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, + ULONG Length, FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry, PUNICODE_STRING FileName, BOOLEAN RestartScan) +{ + if (FileName) { + try { + bool wildcard_found = false; + for (size_t i = 0; i < FileName->Length / sizeof(WCHAR); i++) { + wchar_t c = FileName->Buffer[i]; + if (c == '*' || c == '?') { + wildcard_found = true; + break; + } + } + if (!wildcard_found) { + const OBJECT_ENTRY *enc_entry = FindEntry(FileHandle, FileName); + if (enc_entry) { + OBJECT_ENTRY entry = DecryptEntry(enc_entry); + NTSTATUS status; + switch (FileInformationClass) { + case FileBothDirectoryInformation: + { + if (Length < sizeof(FILE_BOTH_DIR_INFORMATION) - sizeof(WCHAR) + FileName->Length) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + FILE_BOTH_DIR_INFORMATION *info = reinterpret_cast<FILE_BOTH_DIR_INFORMATION *>(FileInformation); + info->NextEntryOffset = 0; + info->FileIndex = 0; + info->CreationTime.QuadPart = 0; + info->LastAccessTime.QuadPart = 0; + info->LastWriteTime.QuadPart = 0; + info->ChangeTime.QuadPart = 0; + info->EndOfFile.QuadPart = entry.Size; + info->AllocationSize.QuadPart = entry.Size; + info->FileAttributes = entry.OffsetToData ? FILE_ATTRIBUTE_READONLY : FILE_ATTRIBUTE_DIRECTORY; + info->FileNameLength = FileName->Length; + info->ShortNameLength = 0; + info->ShortName[0] = 0; + memcpy(info->FileName, FileName->Buffer, FileName->Length); + + IoStatusBlock->Information = sizeof(FILE_BOTH_DIR_INFORMATION) - sizeof(WCHAR) + info->FileNameLength; + IoStatusBlock->Status = STATUS_SUCCESS; + status = STATUS_SUCCESS; + } + break; + case FileIdBothDirectoryInformation: + { + if (Length < sizeof(FILE_ID_BOTH_DIR_INFORMATION) - sizeof(WCHAR) + FileName->Length) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + FILE_ID_BOTH_DIR_INFORMATION *info = reinterpret_cast<FILE_ID_BOTH_DIR_INFORMATION *>(FileInformation); + info->NextEntryOffset = 0; + info->FileIndex = 0; + info->CreationTime.QuadPart = 0; + info->LastAccessTime.QuadPart = 0; + info->LastWriteTime.QuadPart = 0; + info->ChangeTime.QuadPart = 0; + info->EndOfFile.QuadPart = entry.Size; + info->AllocationSize.QuadPart = entry.Size; + info->FileAttributes = entry.OffsetToData ? FILE_ATTRIBUTE_READONLY : FILE_ATTRIBUTE_DIRECTORY; + info->FileNameLength = FileName->Length; + info->ShortNameLength = 0; + info->ShortName[0] = 0; + info->FileId.QuadPart = 0; + memcpy(info->FileName, FileName->Buffer, FileName->Length); + + IoStatusBlock->Information = sizeof(FILE_ID_BOTH_DIR_INFORMATION) - sizeof(WCHAR) + info->FileNameLength; + IoStatusBlock->Status = STATUS_SUCCESS; + status = STATUS_SUCCESS; + } + break; + default: + status = STATUS_NOT_IMPLEMENTED; + break; + } + return status; + } + } + } + catch (...) { + return STATUS_ACCESS_VIOLATION; + } + } + + return TrueNtQueryDirectoryFile(FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, FileInformation, Length, FileInformationClass, ReturnSingleEntry, FileName, RestartScan); +} + +NTSTATUS FileManager::NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key) +{ + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetFile(FileHandle); + if (object) { + OBJECT_ENTRY entry = DecryptEntry(static_cast<const OBJECT_ENTRY *>(object->ref())); + if (!entry.OffsetToData) + return STATUS_INVALID_DEVICE_REQUEST; + + try { + uint64_t file_position; + if (!ByteOffset || (ByteOffset->HighPart == -1 && ByteOffset->LowPart == FILE_USE_FILE_POINTER_POSITION)) + file_position = object->file_position(); + else + file_position = ByteOffset->QuadPart; + + if (file_position + Length > entry.Size) + Length = (file_position < entry.Size) ? entry.Size - static_cast<uint32_t>(file_position) : 0; + + if (ReadFile(&entry, file_position, Buffer, Length)) + object->set_file_position(file_position + Length); + else + Length = 0; + IoStatusBlock->Information = Length; + IoStatusBlock->Status = STATUS_SUCCESS; + return STATUS_SUCCESS; + } catch(...) { + return STATUS_ACCESS_VIOLATION; + } + } + } + + return TrueNtReadFile(FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, Buffer, Length, ByteOffset, Key); +} + +NTSTATUS FileManager::NtCreateSection(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PLARGE_INTEGER MaximumSize, ULONG SectionPageProtection, ULONG AllocationAttributes, HANDLE FileHandle) +{ + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetFile(FileHandle); + if (object) { + OBJECT_ENTRY entry = DecryptEntry(static_cast<const OBJECT_ENTRY *>(object->ref())); + if (!entry.OffsetToData) + return STATUS_INVALID_FILE_FOR_SECTION; + + NTSTATUS status; + LARGE_INTEGER image_size; + if (AllocationAttributes & SEC_IMAGE) { + IMAGE_NT_HEADERS nt_header; + status = ReadImageHeader(&entry, &nt_header); + if (status != STATUS_SUCCESS) + return status; + image_size.QuadPart = nt_header.OptionalHeader.SizeOfImage; + } else { + image_size.QuadPart = entry.Size; + } + status = TrueNtCreateSection(SectionHandle, DesiredAccess | SECTION_MAP_WRITE, ObjectAttributes, &image_size, (AllocationAttributes & SEC_IMAGE) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, SEC_COMMIT, NULL); + if (NT_SUCCESS(status)) { + VirtualObject *section = objects_->Add(OBJECT_SECTION, object->ref(), *SectionHandle, DesiredAccess); + section->set_attributes(AllocationAttributes); + } + return status; + } + } + + return TrueNtCreateSection(SectionHandle, DesiredAccess, ObjectAttributes, MaximumSize, SectionPageProtection, AllocationAttributes, FileHandle); +} + +NTSTATUS FileManager::NtQuerySection(HANDLE SectionHandle, SECTION_INFORMATION_CLASS InformationClass, PVOID InformationBuffer, ULONG InformationBufferSize, PULONG ResultLength) +{ + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetSection(SectionHandle); + if (object && (object->attributes() & SEC_IMAGE)) { + IMAGE_NT_HEADERS nt_header; + OBJECT_ENTRY entry = DecryptEntry(static_cast<const OBJECT_ENTRY *>(object->ref())); + NTSTATUS status = ReadImageHeader(&entry, &nt_header); + if (NT_SUCCESS(status)) { + try { + switch (InformationClass) { + case SectionBasicInformation: + { + if (InformationBufferSize < sizeof(SECTION_BASIC_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + SECTION_BASIC_INFORMATION *info = reinterpret_cast<SECTION_BASIC_INFORMATION *>(InformationBuffer); + memset(info, 0, sizeof(*info)); + info->Attributes = SEC_IMAGE; + info->Size.QuadPart = nt_header.OptionalHeader.SizeOfImage; + if (ResultLength) + *ResultLength = sizeof(SECTION_BASIC_INFORMATION); + } + status = STATUS_SUCCESS; + break; + case SectionImageInformation: + { + if (InformationBufferSize < sizeof(SECTION_IMAGE_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + SECTION_IMAGE_INFORMATION *info = reinterpret_cast<SECTION_IMAGE_INFORMATION *>(InformationBuffer); + memset(info, 0, sizeof(*info)); + info->ImageCharacteristics = nt_header.OptionalHeader.DllCharacteristics; + info->ImageMachineType = nt_header.FileHeader.Machine; + info->ImageSubsystem = nt_header.OptionalHeader.Subsystem; + info->StackCommit = static_cast<ULONG>(nt_header.OptionalHeader.SizeOfStackCommit); + info->StackReserved = static_cast<ULONG>(nt_header.OptionalHeader.SizeOfStackReserve); + info->StackZeroBits = 0; + info->SubSystemVersionHigh = nt_header.OptionalHeader.MajorSubsystemVersion; + info->SubSystemVersionLow = nt_header.OptionalHeader.MinorSubsystemVersion; + if (ResultLength) + *ResultLength = sizeof(SECTION_IMAGE_INFORMATION); + } + status = STATUS_SUCCESS; + break; + case SectionRelocationInformation: + { + if (InformationBufferSize < sizeof(ULONG_PTR)) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + *reinterpret_cast<ULONG_PTR *>(InformationBuffer) = 0; + if (ResultLength) + *ResultLength = sizeof(ULONG_PTR); + } + default: + status = STATUS_NOT_IMPLEMENTED; + break; + } + return status; + } catch(...) { + return STATUS_ACCESS_VIOLATION; + } + } + } + } + + return TrueNtQuerySection(SectionHandle, InformationClass, InformationBuffer, InformationBufferSize, ResultLength); +} + +NTSTATUS FileManager::NtMapViewOfSection(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, SECTION_INHERIT InheritDisposition, ULONG AllocationType, ULONG Win32Protect) +{ + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetSection(SectionHandle); + if (object) { + OBJECT_ENTRY entry = DecryptEntry(static_cast<const OBJECT_ENTRY *>(object->ref())); + NTSTATUS status = TrueNtMapViewOfSection(SectionHandle, ProcessHandle, BaseAddress, ZeroBits, CommitSize, SectionOffset, ViewSize, InheritDisposition, 0, (object->attributes() & SEC_IMAGE) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE); + if (NT_SUCCESS(status)) { + try { + uint64_t offset = (SectionOffset && SectionOffset->QuadPart) ? SectionOffset->QuadPart : 0; + if (object->attributes() & SEC_IMAGE) { + if (offset) + return STATUS_NOT_IMPLEMENTED; + status = ReadImage(&entry, *BaseAddress); + } else { + size_t size = *ViewSize; + if (offset + size > entry.Size) + size = (offset < entry.Size) ? entry.Size - static_cast<uint32_t>(offset) : 0; + ReadFile(&entry, offset, *BaseAddress, size); + if (Win32Protect != PAGE_READWRITE) { + ULONG old_protect; + if (!VirtualProtect(*BaseAddress, *ViewSize, Win32Protect, &old_protect)) + status = STATUS_INVALID_PAGE_PROTECTION; + } + } + if (NT_SUCCESS(status)) { + /*VirtualObject *map = */objects_->Add(OBJECT_MAP, *BaseAddress, ProcessHandle, 0); + } else { + TrueNtUnmapViewOfSection(ProcessHandle, *BaseAddress); + } + } catch(...) { + return STATUS_ACCESS_VIOLATION; + } + } + return status; + } + } + + return TrueNtMapViewOfSection(SectionHandle, ProcessHandle, BaseAddress, ZeroBits, CommitSize, SectionOffset, ViewSize, InheritDisposition, AllocationType, Win32Protect); +} + +NTSTATUS FileManager::NtUnmapViewOfSection(HANDLE ProcessHandle, PVOID BaseAddress) +{ + { + CriticalSection cs(objects_->critical_section()); + + objects_->DeleteRef(BaseAddress, ProcessHandle); + } + + return TrueNtUnmapViewOfSection(ProcessHandle, BaseAddress); +} + +NTSTATUS FileManager::NtQueryVirtualMemory(HANDLE ProcessHandle, PVOID BaseAddress, MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID Buffer, ULONG Length, PULONG ResultLength) +{ + if (MemoryInformationClass == MemoryBasicInformation) { + NTSTATUS status = TrueNtQueryVirtualMemory(ProcessHandle, BaseAddress, MemoryInformationClass, Buffer, Length, ResultLength); + if (NT_SUCCESS(status)) { + MEMORY_BASIC_INFORMATION *info = reinterpret_cast<MEMORY_BASIC_INFORMATION *>(Buffer); + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetMap(ProcessHandle, info->AllocationBase); + if (object && (object->attributes() & SEC_IMAGE)) + info->Type = MEM_IMAGE; + } + return status; + } + + return TrueNtQueryVirtualMemory(ProcessHandle, BaseAddress, MemoryInformationClass, Buffer, Length, ResultLength); +} + +#endif // WIN_DRIVER
\ No newline at end of file diff --git a/runtime/file_manager.h b/runtime/file_manager.h new file mode 100644 index 0000000..7b07abb --- /dev/null +++ b/runtime/file_manager.h @@ -0,0 +1,348 @@ +#ifndef FILE_MANAGER_H +#define FILE_MANAGER_H + +#include "loader.h" +#include "registry_manager.h" + +class CipherRC5; + +typedef struct _FILE_BASIC_INFORMATION { + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + ULONG FileAttributes; +} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; + +typedef enum _SECTION_INFORMATION_CLASS { + SectionBasicInformation, + SectionImageInformation, + SectionRelocationInformation +} SECTION_INFORMATION_CLASS, *PSECTION_INFORMATION_CLASS; + +typedef struct _SECTION_BASIC_INFORMATION { + ULONG BaseAddress; + ULONG Attributes; + LARGE_INTEGER Size; +} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION; + +typedef struct _SECTION_IMAGE_INFORMATION { + PVOID EntryPoint; + ULONG StackZeroBits; + ULONG StackReserved; + ULONG StackCommit; + ULONG ImageSubsystem; + WORD SubSystemVersionLow; + WORD SubSystemVersionHigh; + ULONG Unknown1; + ULONG ImageCharacteristics; + ULONG ImageMachineType; + ULONG Unknown2[3]; +} SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION; + +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L) +#define STATUS_INVALID_IMAGE_FORMAT ((NTSTATUS)0xC000007BL) +#define STATUS_INVALID_PAGE_PROTECTION ((NTSTATUS)0xC0000045L) +#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L) +#define STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L) +#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) +#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L) +#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS)0xC0000034L) +#define STATUS_NO_MORE_ENTRIES ((NTSTATUS)0x8000001AL) +#ifndef STATUS_INVALID_PARAMETER +#define STATUS_INVALID_PARAMETER ((NTSTATUS)0xC000000DL) +#endif +#define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS)0xC0000010L) +#define STATUS_INVALID_FILE_FOR_SECTION ((NTSTATUS)0xC0000020L) + +#define OBJ_HANDLE_TAGBITS 0x00000003L +#define EXHANDLE(x) ((HANDLE)((ULONG_PTR)(x) &~ OBJ_HANDLE_TAGBITS)) + +#define FILE_SUPERSEDE 0x00000000 +#define FILE_OPEN 0x00000001 +#define FILE_CREATE 0x00000002 +#define FILE_OPEN_IF 0x00000003 +#define FILE_OVERWRITE 0x00000004 +#define FILE_OVERWRITE_IF 0x00000005 +#define FILE_MAXIMUM_DISPOSITION 0x00000005 + +#define FILE_SUPERSEDED 0x00000000 +#define FILE_OPENED 0x00000001 +#define FILE_CREATED 0x00000002 +#define FILE_OVERWRITTEN 0x00000003 +#define FILE_EXISTS 0x00000004 +#define FILE_DOES_NOT_EXIST 0x00000005 + +#define FILE_USE_FILE_POINTER_POSITION 0xfffffffe + +#define IMAGE_FILE_MACHINE_I486 0x14D +#define IMAGE_FILE_MACHINE_I586 0x14E + +#define FileBothDirectoryInformation (FILE_INFORMATION_CLASS)0x03 +#define FileBasicInformation (FILE_INFORMATION_CLASS)0x04 +#define FileStandardInformation (FILE_INFORMATION_CLASS)0x05 +#define FileNameInformation (FILE_INFORMATION_CLASS)0x09 +#define FilePositionInformation (FILE_INFORMATION_CLASS)0x0e +#define FileIdBothDirectoryInformation (FILE_INFORMATION_CLASS)0x25 +#define FileAllInformation (FILE_INFORMATION_CLASS)0x12 + +typedef struct _FILE_POSITION_INFORMATION { + LARGE_INTEGER CurrentByteOffset; +} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION; + +typedef struct _FILE_STANDARD_INFORMATION { + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG NumberOfLinks; + BOOLEAN DeletePending; + BOOLEAN Directory; +} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION; + +typedef struct _FILE_NAME_INFORMATION { + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION; + +typedef struct _FILE_INTERNAL_INFORMATION { + LARGE_INTEGER IndexNumber; +} FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION; + +typedef struct _FILE_EA_INFORMATION { + ULONG EaSize; +} FILE_EA_INFORMATION, *PFILE_EA_INFORMATION; + +typedef struct _FILE_ACCESS_INFORMATION { + ACCESS_MASK AccessFlags; +} FILE_ACCESS_INFORMATION, *PFILE_ACCESS_INFORMATION; + +typedef struct _FILE_MODE_INFORMATION { + ULONG Mode; +} FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION; + +typedef struct _FILE_ALIGNMENT_INFORMATION { + ULONG AlignmentRequirement; +} FILE_ALIGNMENT_INFORMATION, *PFILE_ALIGNMENT_INFORMATION; + +typedef struct _FILE_ALL_INFORMATION { + FILE_BASIC_INFORMATION BasicInformation; + FILE_STANDARD_INFORMATION StandardInformation; + FILE_INTERNAL_INFORMATION InternalInformation; + FILE_EA_INFORMATION EaInformation; + FILE_ACCESS_INFORMATION AccessInformation; + FILE_POSITION_INFORMATION PositionInformation; + FILE_MODE_INFORMATION ModeInformation; + FILE_ALIGNMENT_INFORMATION AlignmentInformation; + FILE_NAME_INFORMATION NameInformation; +} FILE_ALL_INFORMATION, *PFILE_ALL_INFORMATION; + +typedef struct _OBJECT_NAME_INFORMATION { + UNICODE_STRING Name; +} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; + +typedef enum _FSINFOCLASS { + FileFsVolumeInformation = 1, + FileFsLabelInformation, // 2 + FileFsSizeInformation, // 3 + FileFsDeviceInformation, // 4 + FileFsAttributeInformation, // 5 + FileFsControlInformation, // 6 + FileFsFullSizeInformation, // 7 + FileFsObjectIdInformation, // 8 + FileFsDriverPathInformation, // 9 + FileFsVolumeFlagsInformation,// 10 + FileFsMaximumInformation +} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS; + +typedef struct _FILE_FS_DEVICE_INFORMATION { + DEVICE_TYPE DeviceType; + ULONG Characteristics; +} FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION; + +typedef struct _FILE_FS_ATTRIBUTE_INFORMATION { + ULONG FileSystemAttributes; + LONG MaximumComponentNameLength; + ULONG FileSystemNameLength; + WCHAR FileSystemName[1]; +} FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION; + +typedef struct _FILE_FS_VOLUME_INFORMATION { + LARGE_INTEGER VolumeCreationTime; + ULONG VolumeSerialNumber; + ULONG VolumeLabelLength; + BOOLEAN SupportsObjects; + WCHAR VolumeLabel[1]; +} FILE_FS_VOLUME_INFORMATION, *PFILE_FS_VOLUME_INFORMATION; + +typedef struct _FILE_BOTH_DIR_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + WCHAR FileName[1]; +} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION; + +typedef struct _FILE_ID_BOTH_DIR_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + LARGE_INTEGER FileId; + WCHAR FileName[1]; +} FILE_ID_BOTH_DIR_INFORMATION, *PFILE_ID_BOTH_DIR_INFORMATION; + +struct OBJECT_DIRECTORY { + uint32_t NumberOfEntries; + // OBJECT_ENTRY Entries[]; +}; + +#define ObjectNameInformation (OBJECT_INFORMATION_CLASS)1 + +struct OBJECT_ENTRY { + uint32_t NameOffset; + uint32_t OffsetToData; + uint32_t Size; + uint32_t Options; +}; + +class Path +{ +public: + Path(wchar_t *str) + { + const wchar_t *last = str; + const wchar_t *cur = str; + while (*cur) { + if (*cur == '\\') { + if (cur > last) + list_.push_back(UnicodeString(last, cur - last)); + last = cur + 1; + } + cur++; + } + if (cur > last) + list_.push_back(UnicodeString(last, cur - last)); + } + + UnicodeString Combine(wchar_t *str) + { + vector<const UnicodeString *> folder_list; + for (size_t i = 0; i < list_.size(); i++) { + folder_list.push_back(&list_[i]); + } + + Path p(str); + for (size_t i = 0; i < p.list_.size(); i++) { + const UnicodeString &folder = p.list_[i]; + if (folder == L".") + continue; + + if (folder == L"..") + folder_list.pop_back(); + else + folder_list.push_back(&folder); + } + + UnicodeString res; + for (size_t i = 0; i < folder_list.size(); i++) { + if (i > 0) + res.append(L"\\", 1); + res.append(folder_list[i]->c_str()); + } + return res; + } + +private: + vector<UnicodeString> list_; +}; + +class HookManager; +class FileManager +{ +public: + FileManager(const uint8_t *data, HMODULE instance, const uint8_t *key, VirtualObjectList *objects); + void HookAPIs(HookManager &hook_manager); + void UnhookAPIs(HookManager &hook_manager); + bool OpenFiles(RegistryManager ®istry_manager); + NTSTATUS NtQueryAttributesFile(POBJECT_ATTRIBUTES ObjectAttributes, PFILE_BASIC_INFORMATION FileInformation); + NTSTATUS NtCreateFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength); + NTSTATUS NtOpenFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess, ULONG OpenOptions); + NTSTATUS NtQueryInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); + NTSTATUS NtQueryVolumeInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, ULONG Length, FS_INFORMATION_CLASS FsInformationClass); + NTSTATUS NtSetInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); + NTSTATUS NtQueryDirectoryFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry, PUNICODE_STRING FileName, BOOLEAN RestartScan); + NTSTATUS NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key); + NTSTATUS NtCreateSection(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PLARGE_INTEGER MaximumSize, ULONG SectionPageProtection, ULONG AllocationAttributes, HANDLE FileHandle); + NTSTATUS NtQuerySection(HANDLE SectionHandle, SECTION_INFORMATION_CLASS InformationClass, PVOID InformationBuffer, ULONG InformationBufferSize, PULONG ResultLength); + NTSTATUS NtMapViewOfSection(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, SECTION_INHERIT InheritDisposition, ULONG AllocationType, ULONG Win32Protect); + NTSTATUS NtUnmapViewOfSection(HANDLE ProcessHandle, PVOID BaseAddress); + NTSTATUS NtQueryVirtualMemory(HANDLE ProcessHandle, PVOID BaseAddress, MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID Buffer, ULONG Length, PULONG ResultLength); +private: + NTSTATUS TrueNtQueryAttributesFile(POBJECT_ATTRIBUTES ObjectAttributes, PFILE_BASIC_INFORMATION FileInformation); + NTSTATUS TrueNtCreateFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength); + NTSTATUS TrueNtOpenFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess, ULONG OpenOptions); + NTSTATUS TrueNtQueryInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); + NTSTATUS TrueNtQueryVolumeInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, ULONG Length, FS_INFORMATION_CLASS FsInformationClass); + NTSTATUS TrueNtSetInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); + NTSTATUS TrueNtQueryDirectoryFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry, PUNICODE_STRING FileName, BOOLEAN RestartScan); + NTSTATUS TrueNtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key); + NTSTATUS TrueNtCreateSection(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PLARGE_INTEGER MaximumSize, ULONG SectionPageProtection, ULONG AllocationAttributes, HANDLE FileHandle); + NTSTATUS TrueNtQuerySection(HANDLE SectionHandle, SECTION_INFORMATION_CLASS InformationClass, PVOID InformationBuffer, ULONG InformationBufferSize, PULONG ResultLength); + NTSTATUS TrueNtMapViewOfSection(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, SECTION_INHERIT InheritDisposition, ULONG AllocationType, ULONG Win32Protect); + NTSTATUS TrueNtUnmapViewOfSection(HANDLE ProcessHandle, PVOID BaseAddress); + NTSTATUS TrueNtQueryVirtualMemory(HANDLE ProcessHandle, PVOID BaseAddress, MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID Buffer, ULONG Length, PULONG ResultLength); + NTSTATUS TrueNtQueryObject(HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength); + OBJECT_DIRECTORY DecryptDirectory(const OBJECT_DIRECTORY *directory_enc) const; + OBJECT_ENTRY DecryptEntry(const OBJECT_ENTRY *entry_enc) const; + bool DecryptString(LPCWSTR str_enc, LPWSTR str, size_t max_size) const; + const OBJECT_ENTRY *FindEntry(HANDLE directory, PUNICODE_STRING object_name); + bool ReadFile(const OBJECT_ENTRY *entry, uint64_t offset, void *dst, size_t size) const; + NTSTATUS ReadImageHeader(const OBJECT_ENTRY *entry, IMAGE_NT_HEADERS *header) const; + NTSTATUS ReadImage(const OBJECT_ENTRY *entry, void *image_base) const; + + HMODULE instance_; + uint32_t key_; + VirtualObjectList *objects_; + const uint8_t *data_; + void *nt_query_attributes_file_; + void *nt_create_file_; + void *nt_open_file_; + void *nt_read_file_; + void *nt_query_information_file_; + void *nt_query_volume_information_file_; + void *nt_set_information_file_; + void *nt_query_directory_file_; + void *nt_close_; + void *nt_create_section_; + void *nt_query_section_; + void *nt_map_view_of_section_; + void *nt_unmap_view_of_section_; + void *nt_query_virtual_memory_; + vector<UnicodeString> file_name_list_; + UnicodeString dos_root_; + UnicodeString nt_root_; + + // no copy ctr or assignment op + FileManager(const FileManager &); + FileManager &operator =(const FileManager &); +}; + +#endif
\ No newline at end of file diff --git a/runtime/hook_manager.cc b/runtime/hook_manager.cc new file mode 100644 index 0000000..575a625 --- /dev/null +++ b/runtime/hook_manager.cc @@ -0,0 +1,738 @@ +#ifdef WIN_DRIVER +#else +#include "common.h" +#include "objects.h" +#include "utils.h" +#include "hook_manager.h" + +/** + * HookManager + */ + +HookManager::HookManager() + : update_count_(0) +{ + +} + +void *HookManager::HookAPI(HMODULE dll, const char *api_name, void *handler, bool show_error, void **result) +{ + void *res = NULL; + void *api_address = InternalGetProcAddress(dll, api_name); + if (api_address) { + Begin(); + HookedAPI *hooked_api = new HookedAPI(); + if (hooked_api->Hook(api_address, handler, result)) { + api_list_.push_back(hooked_api); + res = hooked_api->old_handler(); + } else { + delete hooked_api; + } + End(); + } + + if (!res && show_error) { + wchar_t error[512] = {}; + { + // string "Error at hooking API \"%S\"\n" + wchar_t str[] = { L'E', L'r', L'r', L'o', L'r', L' ', L'a', L't', L' ', L'h', L'o', L'o', L'k', L'i', L'n', L'g', L' ', L'A', L'P', L'I', L' ', L'\"', L'%', L'S', L'\"', L'\n', 0 }; + swprintf_s(error, str, api_name); + } + if (api_address){ + int n = 32; + wchar_t line[100] = {}; + { + // string "Dumping first %d bytes:\n" + wchar_t str[] = { L'D', L'u', L'm', L'p', L'i', L'n', L'g', L' ', L'f', L'i', L'r', L's', L't', L' ', L'%', L'd', L' ', L'b', L'y', L't', L'e', L's', L':', L'\n', 0 }; + swprintf_s(line, str, n); + } + wcscat_s(error, line); + for (int i = 0; i < n; i++) { + wchar_t str[] = { L'%', L'0', L'2', L'X', (i % 16 == 15) ? L'\n' : L' ', 0}; + swprintf_s(line, str, reinterpret_cast<uint8_t *>(api_address)[i]); + wcscat_s(error, line); + } + } + ShowMessage(error); + ::TerminateProcess(::GetCurrentProcess(), 0xDEADC0DE); + } + + return res; +} + +bool HookManager::UnhookAPI(void *handler) +{ + if (!handler) + return false; + + bool res = false; + Begin(); + for (size_t i = 0; i < api_list_.size(); i++) { + HookedAPI *hooked_api = api_list_[i]; + if (hooked_api->old_handler() == handler) { + api_list_.erase(i); + hooked_api->Unhook(); + delete hooked_api; + res = true; + break; + } + } + End(); + return res; +} + +void HookManager::GetThreads() +{ + HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + if (h == INVALID_HANDLE_VALUE) + return; + + THREADENTRY32 thread_entry; + thread_entry.dwSize = sizeof(thread_entry); + if (Thread32First(h, &thread_entry)) { + DWORD process_id = GetCurrentProcessId(); + DWORD thread_id = GetCurrentThreadId(); + + do { + if (thread_entry.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(thread_entry.th32OwnerProcessID)) + { + if (thread_entry.th32OwnerProcessID == process_id && thread_entry.th32ThreadID != thread_id) { + HANDLE thread = ::OpenThread(THREAD_SUSPEND_RESUME, FALSE, thread_entry.th32ThreadID); + if (thread) + thread_list_.push_back(thread); + } + } + thread_entry.dwSize = sizeof(thread_entry); + } while (Thread32Next(h, &thread_entry)); + } + + ::CloseHandle(h); +} + +void HookManager::SuspendThreads() +{ + for (size_t i = 0; i < thread_list_.size(); i++) { + ::SuspendThread(thread_list_[i]); + } +} + +void HookManager::ResumeThreads() +{ + for (size_t i = 0; i < thread_list_.size(); i++) { + ::ResumeThread(thread_list_[i]); + } +} + +void HookManager::FreeThreads() +{ + for (size_t i = 0; i < thread_list_.size(); i++) { + ::CloseHandle(thread_list_[i]); + } + thread_list_.clear(); +} + +void HookManager::Begin() +{ + if (!update_count_) { + GetThreads(); + SuspendThreads(); + } + update_count_++; +} + +void HookManager::End() +{ + update_count_--; + if (!update_count_) { + ResumeThreads(); + FreeThreads(); + } +} + +/** + * HookedAPI + */ + +static bool PutJump(uint8_t *address, const uint8_t *jump_dest) +{ + INT64 offset = reinterpret_cast<uint64_t>(jump_dest) - reinterpret_cast<uint64_t>(address) - 5; + if (offset < INT_MIN || offset > INT_MAX) + return false; + + uint8_t buff[5]; + buff[0] = 0xE9; + *(reinterpret_cast<uint32_t *>(buff + 1)) = static_cast<uint32_t>(offset); + + return FALSE != WriteProcessMemory(GetCurrentProcess(), address, buff, sizeof(buff), NULL); +} + +static bool PutJumpMem(uint8_t *address, const uint8_t *memory) +{ +#ifdef _WIN64 + // offset is relative + INT64 offset = reinterpret_cast<uint64_t>(memory) - reinterpret_cast<uint64_t>(address) - 6; + if (offset < INT_MIN || offset > INT_MAX) + return false; +#else + // offset is absolute + uint32_t offset = reinterpret_cast<uint32_t>(memory); +#endif + + uint8_t buff[6]; + buff[0] = 0xFF; + buff[1] = 0x25; + *(reinterpret_cast<uint32_t *>(buff + 2)) = static_cast<uint32_t>(offset); + + return FALSE != WriteProcessMemory(GetCurrentProcess(), address, buff, sizeof(buff), NULL); +} + +enum eCommandType +{ + CT_UNKNOWN = 0, + CT_JMP, + CT_RET +}; + +struct sCommandInfo +{ + DWORD dwSize; + DWORD dwRelOffset; + eCommandType cmdType; +}; + +#define C_66 0x00000001 // 66-prefix +#define C_67 0x00000002 // 67-prefix +#define C_LOCK 0x00000004 // lock +#define C_REP 0x00000008 // repz/repnz +#define C_SEG 0x00000010 // seg-prefix +#define C_OPCODE2 0x00000020 // 2nd opcode present (1st == 0F) +#define C_MODRM 0x00000040 // modrm present +#define C_SIB 0x00000080 // sib present + +bool GetInstructionSize(const byte *pOpCode, sCommandInfo &info) +{ + const byte *opcode = pOpCode; + +// BYTE disasm_seg = 0; // CS DS ES SS FS GS +// BYTE disasm_rep = 0; // REPZ/REPNZ + BYTE disasm_opcode = 0; // opcode + BYTE disasm_opcode2 = 0; // used when opcode == 0F + BYTE disasm_modrm = 0; // modxxxrm + BYTE disasm_sib = 0; // scale-index-base +#ifdef _WIN64 + BYTE disasm_preffix = {0}; +#endif + +// DWORD disasm_len = 0; // 0 if error + DWORD disasm_flag = 0; // C_xxx + DWORD disasm_memsize = 0; // value = disasm_mem + DWORD disasm_datasize = 0; // value = disasm_data + DWORD disasm_defdata = 4; // == C_66 ? 2 : 4 + DWORD disasm_defmem = 4; // == C_67 ? 2 : 4 + DWORD disasm_offset = 0; + + BYTE mod = 0; + BYTE rm = 0; + + if (! pOpCode) return false; + + info.dwSize = 0; + info.dwRelOffset = 0; + info.cmdType = CT_UNKNOWN; + +RETRY: + + disasm_opcode = *opcode ++; + + switch (disasm_opcode) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0A: case 0x0B: + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x18: case 0x19: case 0x1A: case 0x1B: + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x28: case 0x29: case 0x2A: case 0x2B: + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x38: case 0x39: case 0x3A: case 0x3B: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8A: case 0x8B: + case 0x8C: case 0x8D: case 0x8E: + case 0xD0: case 0xD1: case 0xD2: case 0xD3: + case 0xD8: case 0xD9: case 0xDA: case 0xDB: + case 0xDC: case 0xDD: case 0xDE: case 0xDF: + disasm_flag |= C_MODRM; + break; + + case 0x04: case 0x05: case 0x0C: case 0x0D: + case 0x14: case 0x15: case 0x1C: case 0x1D: + case 0x24: case 0x25: case 0x2C: case 0x2D: + case 0x34: case 0x35: case 0x3C: case 0x3D: + case 0xA8: case 0xA9: + + if (disasm_opcode & 1) + { + disasm_datasize += disasm_defdata; + } + else + { + disasm_datasize ++; + } + break; + + case 0xA0: case 0xA1: case 0xA2: case 0xA3: + + if (disasm_opcode & 1) + { + #ifdef _WIN64 + if (!(disasm_flag & C_66) && (disasm_preffix & 8)) + { + disasm_datasize += 8; + } + else + #endif + { + disasm_datasize += disasm_defdata; + } + } + else + { + disasm_datasize ++; + } + break; + + case 0x06: case 0x07: case 0x0E: + case 0x16: case 0x17: case 0x1E: case 0x1F: + case 0x27: case 0x2F: + case 0x37: case 0x3F: + case 0x60: case 0x61: + case 0xCE: + #ifdef _WIN64 + return false; + #else + break; + #endif + + case 0x26: case 0x2E: + case 0x36: case 0x3E: + case 0x64: case 0x65: + disasm_flag |= C_SEG; + goto RETRY; + + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4A: case 0x4B: + case 0x4C: case 0x4D: case 0x4E: case 0x4F: + #ifdef _WIN64 + disasm_preffix = disasm_opcode; + goto RETRY; + #else + break; + #endif + + case 0x50: case 0x51: case 0x52: case 0x53: + case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5A: case 0x5B: + case 0x5C: case 0x5D: case 0x5E: case 0x5F: + case 0x6C: case 0x6D: case 0x6E: case 0x6F: + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9B: case 0x9C: + case 0x9D: case 0x9E: case 0x9F: + case 0xA4: case 0xA5: case 0xA6: case 0xA7: + case 0xAA: case 0xAB: case 0xAC: case 0xAD: + case 0xAE: case 0xAF: + case 0xC3: case 0xC9: case 0xCB: case 0xCC: + case 0xCF: + case 0xD7: + case 0xEC: case 0xED: case 0xEE: case 0xEF: + case 0xF4: case 0xF5: case 0xF8: case 0xF9: + case 0xFA: case 0xFB: case 0xFC: case 0xFD: + break; + + case 0x62: + case 0xC4: case 0xC5: + #ifdef _WIN64 + return false; + #else + disasm_flag |= C_MODRM; + break; + #endif + + case 0x66: + disasm_flag |= C_66; + disasm_defdata = 2; + goto RETRY; + + case 0x67: + disasm_flag |= C_67; + disasm_defmem = 2; + goto RETRY; + + case 0x69: + case 0x81: + case 0xC1: + disasm_flag |= C_MODRM; + disasm_datasize += disasm_defdata; + break; + + case 0x6A: + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7A: case 0x7B: + case 0x7C: case 0x7D: case 0x7E: case 0x7F: + case 0xB0: case 0xB1: case 0xB2: case 0xB3: + case 0xB4: case 0xB5: case 0xB6: case 0xB7: + case 0xCD: + case 0xE0: case 0xE1: case 0xE2: case 0xE3: + case 0xE4: case 0xE5: case 0xE6: case 0xE7: + disasm_datasize ++; + break; + + case 0xEB: + info.cmdType = CT_JMP; + disasm_offset = (DWORD) (opcode - pOpCode); + disasm_datasize ++; + break; + + case 0x8F: + if ((*opcode >> 3) & 7) + return false; + disasm_flag |= C_MODRM; + break; + + case 0x9A: case 0xEA: + #ifdef _WIN64 + return false; + #else + disasm_datasize += (disasm_defdata + 2); + break; + #endif + + case 0x68: + disasm_datasize += disasm_defdata; + break; + + case 0xB8: case 0xB9: case 0xBA: case 0xBB: + case 0xBC: case 0xBD: case 0xBE: case 0xBF: +#ifdef _WIN64 + if (!(disasm_flag & C_66) && (disasm_preffix & 8)) + disasm_datasize += 8; + else +#endif + disasm_datasize += disasm_defdata; + break; + + + //case 0x68: + //case 0xB8: case 0xB9: case 0xBA: case 0xBB: + //case 0xBC: case 0xBD: case 0xBE: case 0xBF: + // disasm_datasize += disasm_defdata; + // break; + + case 0xE8: case 0xE9: + if (disasm_defdata == 2) + return false; + disasm_offset = (DWORD) (opcode - pOpCode); + disasm_datasize += disasm_defdata; + break; + + case 0x6B: + case 0x80: case 0x82: case 0x83: + case 0xC0: + disasm_flag |= C_MODRM; + disasm_datasize ++; + break; + + case 0xC2: + disasm_datasize += 2; + break; + + case 0xC6: case 0xC7: + if ((*opcode >> 3) & 7) + return false; + disasm_flag |= C_MODRM; + if (disasm_opcode & 1) + { + disasm_datasize += disasm_defdata; + } + else + { + disasm_datasize ++; + } + break; + + case 0xC8: + disasm_datasize += 3; + break; + + case 0xCA: + disasm_datasize += 2; + break; + + case 0xD4: case 0xD5: + #ifdef _WIN64 + return false; + #else + disasm_datasize ++; + break; + #endif + + case 0xF0: + disasm_flag |= C_LOCK; + goto RETRY; + + case 0xF2: case 0xF3: + disasm_flag |= C_REP; + goto RETRY; + + case 0xF6: case 0xF7: + disasm_flag |= C_MODRM; + if (((*opcode >> 3) & 7) < 2) + { + if (disasm_opcode & 1) + { + disasm_datasize += disasm_defdata; + } + else + { + disasm_datasize ++; + } + } + break; + + case 0xFE: + if (((*opcode >> 3) & 7) > 1) + return false; + disasm_flag |= C_MODRM; + break; + + case 0xFF: + if (((*opcode >> 3) & 7) == 7) + return false; + disasm_flag |= C_MODRM; + break; + + case 0x0F: + + disasm_flag |= C_OPCODE2; + disasm_opcode2 = *opcode ++; + + switch (disasm_opcode2) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9A: case 0x9B: + case 0x9C: case 0x9D: case 0x9E: case 0x9F: + case 0xA3: case 0xA5: case 0xAB: case 0xAD: + case 0xAF: + case 0xB0: case 0xB1: case 0xB2: case 0xB3: + case 0xB4: case 0xB5: case 0xB6: case 0xB7: + case 0xBB: + case 0xBC: case 0xBD: case 0xBE: case 0xBF: + case 0xC0: case 0xC1: + disasm_flag |= C_MODRM; + break; + + case 0x06: + case 0x08: case 0x09: case 0x0A: case 0x0B: + case 0xA0: case 0xA1: case 0xA2: case 0xA8: + case 0xA9: case 0xAA: + case 0xC8: case 0xC9: case 0xCA: case 0xCB: + case 0xCC: case 0xCD: case 0xCE: case 0xCF: + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8A: case 0x8B: + case 0x8C: case 0x8D: case 0x8E: case 0x8F: + if (disasm_defdata == 2) + return false; + disasm_offset = (DWORD) (opcode - pOpCode); + disasm_datasize += disasm_defdata; + break; + + case 0xA4: case 0xAC: + case 0xBA: + disasm_datasize ++; + disasm_flag |= C_MODRM; + break; + + default: + return false; + } + + default: + return false; + + } + + if (disasm_flag & C_MODRM) + { + disasm_modrm = *opcode ++; + mod = disasm_modrm & 0xC0; + rm = disasm_modrm & 0x07; + + if (mod != 0xC0) + { + if (mod == 0x40) disasm_memsize ++; + if (mod == 0x80) disasm_memsize += disasm_defmem; + + if (disasm_defmem == 2) // modrm16 + { + if ((mod == 0x00) && (rm == 0x06)) + { + disasm_memsize += 2; + } + } + else // modrm32 + { + if (rm == 0x04) + { + disasm_flag |= C_SIB; + disasm_sib = *opcode ++; + rm = disasm_sib & 0x07; + } + + if ((mod == 0x00) && (rm == 0x05)) + { + + #ifdef _WIN64 + if (!(disasm_flag & C_SIB)) + disasm_offset = (DWORD) (opcode - pOpCode); + #endif + disasm_memsize += 4; + } + } + } + } + + info.dwSize =(DWORD) (opcode - pOpCode) + disasm_memsize + disasm_datasize; + info.dwRelOffset = disasm_offset; + + return true; +} + +size_t MoveCode(byte *&pSrcOriginal, byte *pDst, size_t nNeedBytes) +{ + size_t nBytes = 0; + byte *pSrc = pSrcOriginal; + sCommandInfo ii; + while (nBytes < nNeedBytes) + { + if (!GetInstructionSize(pSrc, ii)) + return 0; // error + if (nBytes == 0 && ii.cmdType == CT_JMP && ii.dwSize - ii.dwRelOffset == 1) + { // this is a short jump and we need to follow it + ptrdiff_t offset = static_cast<char>(pSrc[ii.dwSize - 1]); + pSrcOriginal += offset + ii.dwSize; // skip JMP XX + pSrc = pSrcOriginal; + continue; + } + memcpy(pDst, pSrc, ii.dwSize); // copy original bytes + if (ii.dwRelOffset) + *reinterpret_cast<int32_t*>(pDst + ii.dwRelOffset) = static_cast<int32_t>(pSrc + *reinterpret_cast<int32_t*>(pSrc + ii.dwRelOffset) - pDst); + pSrc += ii.dwSize; + pDst += ii.dwSize; + nBytes += ii.dwSize; + } + return nBytes; // return number of bytes copied +} + +size_t HookedAPI::page_size_ = 0; + +HookedAPI::HookedAPI() + : size_(0), api_(NULL), old_handler_(NULL), crc_(0) +{ + +} + +bool HookedAPI::Hook(void *api, void *handler, void **result) +{ + if (!page_size_) { + SYSTEM_INFO system_info; + GetSystemInfo(&system_info); + page_size_ = (system_info.dwPageSize > 2048) ? system_info.dwPageSize : 2048; + } + uint8_t *p = static_cast<uint8_t *>(api); + + // alloc virtual memory +#ifdef _WIN64 + for (size_t i = 0; i < 0x70000000; i += page_size_) { + old_handler_ = ::VirtualAlloc(p + i, page_size_, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if (old_handler_) + break; + } +#else + old_handler_ = ::VirtualAlloc(NULL, page_size_, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#endif + + if (!old_handler_) + return false; + + uint8_t *memory = static_cast<uint8_t *>(old_handler_); + if (result) + *result = memory; + + // structure of the block: + // some api commands + // jmp api + 5 + // original commands + // jmp [handler] + // handler + + // copy api code to the new place + size_ = MoveCode(p, memory, 5); + if (!size_) + return false; + + // add JMP command + if (!PutJump(memory + size_, p + size_)) + return false; + + // copy original commands + memcpy(memory + size_ + 5, p, size_); + + // jmp [handler] + uint8_t *jump = memory + size_ * 2 + 5; + if (!PutJumpMem(jump, jump + 6)) + return false; + + // put handler to [handler] + *(reinterpret_cast<void **>(jump + 6)) = handler; + + // put JMP at the beginning of the API + if (!PutJump(p, jump)) + return false; + + api_ = p; // this line should be below MoveCode, because pAPI can be corrected by it + crc_ = *reinterpret_cast<uint32_t *>(p + 1); + + DWORD old_protect; + VirtualProtect(old_handler_, page_size_, PAGE_EXECUTE_READ, &old_protect); + + return true; +} + +void HookedAPI::Unhook() +{ + if (!api_) + return; + + // check CRC + uint8_t *p = static_cast<uint8_t *>(api_); + if (*p == 0xE9 && *reinterpret_cast<uint32_t *>(p + 1) == crc_) { + // put original bytes back + WriteProcessMemory(GetCurrentProcess(), api_, reinterpret_cast<uint8_t *>(old_handler_) + size_ + 5, size_, NULL); + VirtualFree(old_handler_, 0, MEM_RELEASE); + } else { + // API hooked by another code + WriteProcessMemory(GetCurrentProcess(), static_cast<uint8_t *>(old_handler_) + size_ * 2 + 5 + 6, &old_handler_, sizeof(old_handler_), NULL); + } + + // cleanup + size_ = 0; + api_ = old_handler_ = NULL; +} + +#endif
\ No newline at end of file diff --git a/runtime/hook_manager.h b/runtime/hook_manager.h new file mode 100644 index 0000000..dff44bf --- /dev/null +++ b/runtime/hook_manager.h @@ -0,0 +1,40 @@ +#ifndef HOOK_MANAGER_H +#define HOOK_MANAGER_H + +class HookedAPI +{ +public: + HookedAPI(); + bool Hook(void *api, void *handler, void **result); + void Unhook(); + void *old_handler() const { return old_handler_; } +private: + static size_t page_size_; + size_t size_; + void *api_; + void *old_handler_; + uint32_t crc_; +}; + +class HookManager +{ +public: + HookManager(); + void Begin(); + void End(); + void *HookAPI(HMODULE dll, const char *api_name, void *handler, bool show_error = true, void **result = NULL); + bool UnhookAPI(void * handler); +private: + HookManager(const HookManager &src); + HookManager & operator = (const HookManager &);// block the assignment operator + void GetThreads(); + void SuspendThreads(); + void ResumeThreads(); + void FreeThreads(); + + vector<HookedAPI *> api_list_; + vector<HANDLE> thread_list_; + size_t update_count_; +}; + +#endif
\ No newline at end of file diff --git a/runtime/hwid.cc b/runtime/hwid.cc new file mode 100644 index 0000000..e7d1bac --- /dev/null +++ b/runtime/hwid.cc @@ -0,0 +1,688 @@ +#include "common.h" +#include "objects.h" +#include "utils.h" +#include "hwid.h" +#include "core.h" +#include "crypto.h" + +#ifdef __unix__ +#include <mntent.h> +#include <dirent.h> +#include <net/if.h> +#include <pthread.h> +#endif +#ifdef VMP_GNU +EXPORT_API int WINAPI ExportedGetCurrentHWID(char *buffer, int size) __asm__ ("ExportedGetCurrentHWID"); +#endif +#ifdef WIN_DRIVER +#include <ntddndis.h> +extern "C" { + NTSYSAPI + NTSTATUS + NTAPI + ZwCreateEvent ( + PHANDLE EventHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes, + EVENT_TYPE EventType, + BOOLEAN InitialState + ); + + NTSYSAPI + NTSTATUS + NTAPI + ZwWaitForSingleObject( + HANDLE Handle, + BOOLEAN Alertable, + PLARGE_INTEGER Timeout +); +} +#endif + +int WINAPI ExportedGetCurrentHWID(char *buffer, int size) +{ + HardwareID *hardware_id = Core::Instance()->hardware_id(); + return hardware_id ? hardware_id->GetCurrent(buffer, size) : 0; +} + +/** + * HardwareID + */ + +#ifdef WIN_DRIVER +bool GetRegValue(LPCWSTR reg_path, LPCWSTR value_name, LPWSTR buffer, size_t *size) +{ + UNICODE_STRING unicode_reg_path, unicode_value_name; + OBJECT_ATTRIBUTES object_attributes; + NTSTATUS status; + HANDLE key_handle; + ULONG information_size; + KEY_VALUE_PARTIAL_INFORMATION *information; + bool res = false; + + RtlInitUnicodeString(&unicode_reg_path, reg_path); + RtlInitUnicodeString(&unicode_value_name, value_name); + InitializeObjectAttributes(&object_attributes, &unicode_reg_path, OBJ_CASE_INSENSITIVE, NULL, NULL); + status = ZwOpenKey(&key_handle, KEY_QUERY_VALUE, &object_attributes); + if (NT_SUCCESS(status)) { + information_size = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + MAX_PATH * sizeof(WCHAR); + information = reinterpret_cast<KEY_VALUE_PARTIAL_INFORMATION*>(new uint8_t[information_size]); + status = ZwQueryValueKey(key_handle, &unicode_value_name, KeyValuePartialInformation, information, information_size, &information_size); + if (NT_SUCCESS(status)) { + size_t len = information->DataLength / sizeof(wchar_t); + if (*size < len + 1) { + *size = len + 1; + } else { + RtlCopyMemory(buffer, information->Data, information->DataLength); + buffer[len] = 0; + *size = wcslen(buffer); + res = true; + } + } + delete [] information; + ZwClose(key_handle); + } + return res; +} +#endif + +HardwareID::HardwareID() + : block_count_(0), start_block_(0) +{ + uint64_t timestamp = __rdtsc(); // exactly 8 bytes + timestamp ^= ~timestamp << 32; // remove zeroes at the beginning + blocks_ = new CryptoContainer(sizeof(uint32_t) * MAX_BLOCKS, reinterpret_cast<uint8_t *>(×tamp)); + + // old methods + GetCPU(0); + GetCPU(1); + start_block_ = block_count_; + // new methods, we'll return HWID starting from this DWORD + GetCPU(2); + GetMachineName(); + GetHDD(); + GetMacAddresses(); +} + +HardwareID::~HardwareID() +{ + delete blocks_; +} + +void HardwareID::AddBlock(const void *p, size_t size, BlockType type) +{ + if (block_count_ == MAX_BLOCKS) return; // no free space + + SHA1 hash; + hash.Input(reinterpret_cast<const uint8_t *>(p), size); + uint32_t block = __builtin_bswap32(*reinterpret_cast<const uint32_t *>(hash.Result())); + + block &= ~TYPE_MASK; // zero two lower bits + block |= type & TYPE_MASK; // set type bits + + // check existing blocks + for (size_t i = block_count_; i > start_block_; i--) { + uint32_t prev_block = blocks_->GetDWord((i - 1) * sizeof(uint32_t)); + if (prev_block == block) + return; + if ((prev_block & TYPE_MASK) != (block & TYPE_MASK)) + break; + } + + blocks_->SetDWord(block_count_ * sizeof(uint32_t), block); + block_count_++; +} + +void HardwareID::GetCPU(uint8_t method) +{ + uint32_t old_block_count = block_count_; + +#ifdef WIN_DRIVER + KAFFINITY system_mask = KeQueryActiveProcessors(); + KAFFINITY mask = 1; +#endif +#ifdef VMP_GNU + // set process affinity mask to system affinity mask +#ifdef __APPLE__ + //FIXME + if (0) { +#else + cpu_set_t process_mask, system_mask; + memset(&system_mask, 0xFF, sizeof(system_mask)); + if (0 == sched_getaffinity(0, sizeof(process_mask), &process_mask)) { + sched_setaffinity(0, sizeof(system_mask), &system_mask); //try all CPUs, will set MAX CPUs + sched_getaffinity(0, sizeof(system_mask), &system_mask); //get MAX CPUs +#endif +#else +#ifndef WIN_DRIVER + DWORD_PTR process_mask, system_mask; + HANDLE process = GetCurrentProcess(); + if (GetProcessAffinityMask(process, &process_mask, &system_mask)) { + if (process_mask != system_mask) + SetProcessAffinityMask(process, system_mask); + DWORD_PTR mask = 1; + HANDLE thread = GetCurrentThread(); +#endif +#endif +#ifdef VMP_GNU + // set thread affinity mask to mask +#ifdef __APPLE__ + //FIXME + while (false) { + if (false) { +#else + for (size_t i = 0; i < sizeof(system_mask) * 8; i++) { + if (__CPU_ISSET_S(i, sizeof(system_mask), &system_mask)) { + cpu_set_t mask; + __CPU_ZERO_S(sizeof(mask), &mask); + __CPU_SET_S(i, sizeof(mask), &mask); + sched_setaffinity(0, sizeof(mask), &mask); +#endif +#else + for (size_t i = 0; i < sizeof(mask) * 8; i++) { + if (system_mask & mask) { +#ifdef WIN_DRIVER + KeSetSystemAffinityThread(mask); +#else + DWORD_PTR old_mask = SetThreadAffinityMask(thread, mask); + Sleep(0); +#endif +#endif + ProcessCPU(method); +#ifdef VMP_GNU + // set thread affinity mask back to old_mask +#ifdef __APPLE__ + //FIXME +#else + //do nothing +#endif +#else +#ifdef WIN_DRIVER + KeRevertToUserAffinityThread(); +#else + SetThreadAffinityMask(thread, old_mask); +#endif +#endif + } +#ifndef VMP_GNU + mask <<= 1; +#endif + } +#ifndef WIN_DRIVER +#ifdef VMP_GNU + // set process affinity mask back to process_mask +#ifdef __APPLE__ + //FIXME +#else + sched_setaffinity(0, sizeof(process_mask), &process_mask); +#endif +#else + if (process_mask != system_mask) + SetProcessAffinityMask(process, process_mask); +#endif + } +#endif + + if (old_block_count == block_count_) + ProcessCPU(method); +} + +void HardwareID::ProcessCPU(uint8_t method) +{ + int info[4]; + __cpuid(info, 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); + } + + AddBlock(info, sizeof(info), BLOCK_CPU); +} + +void HardwareID::GetMachineName() +{ +#ifdef __APPLE__ + CFStringRef computer_name = SCDynamicStoreCopyComputerName(NULL, NULL); + if (!computer_name) + return; + + CFIndex len = CFStringGetLength(computer_name); + CFIndex size = CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8); + char *buf = new char[size]; + if (CFStringGetCString(computer_name, buf, size, kCFStringEncodingUTF8)) + AddBlock(buf, strlen(buf), BLOCK_HOST); + delete [] buf; + CFRelease(computer_name); +#elif defined(__unix__) + char buf[HOST_NAME_MAX+1] = {0}; + if (0 == gethostname(buf, HOST_NAME_MAX)) + AddBlock(buf, strlen(buf), BLOCK_HOST); +#elif defined(WIN_DRIVER) + #define MAX_COMPUTERNAME_LENGTH 31 + + wchar_t buf[MAX_COMPUTERNAME_LENGTH + 1]; + size_t size = _countof(buf); + + if (GetRegValue(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ComputerName\\ComputerName", L"ComputerName", buf, &size) || + GetRegValue(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ComputerName\\ActiveComputerName", L"ComputerName", buf, &size)) { + AddBlock(buf, size * sizeof(wchar_t), BLOCK_HOST); + } +#else + HMODULE dll = LoadLibraryA(VMProtectDecryptStringA("kernel32.dll")); + if (!dll) + return; + + typedef ULONG (WINAPI *GET_COMPUTER_NAME) (wchar_t *, uint32_t *); + GET_COMPUTER_NAME get_computer_name = reinterpret_cast<GET_COMPUTER_NAME>(InternalGetProcAddress(dll, VMProtectDecryptStringA("GetComputerNameW"))); + + if (get_computer_name) { + wchar_t buf[MAX_COMPUTERNAME_LENGTH + 1]; + uint32_t size = _countof(buf); + + if (get_computer_name(buf, &size)) + AddBlock(buf, size * sizeof(wchar_t), BLOCK_HOST); + } + + FreeLibrary(dll); +#endif +} + +void HardwareID::ProcessMAC(const uint8_t *p, size_t size) +{ + // 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 + uint32_t 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, size, BLOCK_MAC); +} + +void HardwareID::GetMacAddresses() +{ +#ifdef __APPLE__ + ifaddrs *addrs; + if (getifaddrs(&addrs) == 0) { + uint32_t block_count_no_mac = block_count_; + const uint8_t *mac = NULL; + size_t size = 0; + for (ifaddrs *cur_addr = addrs; cur_addr != 0; cur_addr = cur_addr->ifa_next) { + if (cur_addr->ifa_addr->sa_family != AF_LINK) + continue; + + const sockaddr_dl *dl_addr = reinterpret_cast<const sockaddr_dl *>(cur_addr->ifa_addr); + if (dl_addr->sdl_type == IFT_ETHER) { + mac = reinterpret_cast<const uint8_t *>(&dl_addr->sdl_data[dl_addr->sdl_nlen]); + size = dl_addr->sdl_alen; + ProcessMAC(mac, size); + } + } + if (block_count_no_mac == block_count_ && mac && size) + AddBlock(mac, size, BLOCK_MAC); + freeifaddrs(addrs); + } +#elif defined(__unix__) + std::string dir_name("/sys/class/net/"); + if (DIR *dir = opendir(dir_name.c_str())) { + uint32_t block_count_no_mac = block_count_; + uint8_t mac[6]; + size_t size = 0; + while (struct dirent *entry = readdir(dir)) { + // skip "." and ".." + if (entry->d_name[0] == '.') { + if (entry->d_name[1] == 0 || (entry->d_name[1] == '.' && entry->d_name[2] == 0)) + continue; + } + + struct stat st; + if (fstatat(dirfd(dir), entry->d_name, &st, 0) >= 0 && S_ISDIR(st.st_mode)) { + std::string file_name = dir_name + entry->d_name + "/address"; + if (FILE *faddr = fopen(file_name.c_str(), "r")) { + char addr[18] = {0}; + if (fgets(addr, sizeof(addr) - 1, faddr)) { + uint8_t m[6]; + size_t c = sscanf_s(addr, "%02hx:%02hx:%02hx:%02hx:%02hx:%02hx", + m+0, m+1, m+2, m+3, m+4, m+5); + if (c == 6 && m[0]+m[1]+m[2]+m[3]+m[4]+m[5] != 0) { + memcpy(mac, m, sizeof(mac)); + size = c; + ProcessMAC(mac, size); + } + } + fclose(faddr); + } + } + } + closedir(dir); + if (block_count_no_mac == block_count_ && size) + AddBlock(mac, size, BLOCK_MAC); + } +#elif defined(WIN_DRIVER) + UNICODE_STRING unicode_string; + OBJECT_ATTRIBUTES object_attributes; + NTSTATUS status; + HANDLE key_handle, file_handle, event_handle; + IO_STATUS_BLOCK status_block; + ULONG code = OID_802_3_CURRENT_ADDRESS; + uint8_t mac[6]; + size_t size = 0; + + InitializeObjectAttributes(&object_attributes, NULL, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); + status = ZwCreateEvent(&event_handle, EVENT_ALL_ACCESS, &object_attributes, NotificationEvent, FALSE); + if (!NT_SUCCESS(status)) + return; + + RtlInitUnicodeString(&unicode_string, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Adapters"); + InitializeObjectAttributes(&object_attributes, &unicode_string, OBJ_CASE_INSENSITIVE, NULL, NULL); + status = ZwOpenKey(&key_handle, GENERIC_READ, &object_attributes); + if (NT_SUCCESS(status)) { + uint32_t block_count_no_mac = block_count_; + ULONG sub_key_size = sizeof(KEY_BASIC_INFORMATION) + sizeof(wchar_t) * MAX_PATH; + KEY_BASIC_INFORMATION *sub_key_value = static_cast<KEY_BASIC_INFORMATION *>(ExAllocatePool(PagedPool, sub_key_size)); + wchar_t *service_name = static_cast<wchar_t *>(ExAllocatePool(PagedPool, sizeof(wchar_t) * MAX_PATH)); + + ULONG ret_size; + for (ULONG i = 0; NT_SUCCESS(ZwEnumerateKey(key_handle, i, KeyBasicInformation, sub_key_value, sub_key_size, &ret_size)); i++) { + if (sub_key_value->NameLength > (MAX_PATH - 10) * sizeof(wchar_t)) + continue; + + if (sub_key_value->NameLength == 18 && _wcsnicmp(sub_key_value->Name, L"NdisWanIp", 9) == 0) + continue; + + RtlZeroMemory(service_name, sizeof(wchar_t) * MAX_PATH); +#if WDK_NTDDI_VERSION > NTDDI_WIN7 + wcscat_s(service_name, MAX_PATH, L"\\??\\"); +#else + wcscat(service_name, L"\\??\\"); +#endif + RtlCopyMemory(service_name + wcslen(service_name), sub_key_value->Name, sub_key_value->NameLength); + RtlInitUnicodeString(&unicode_string, service_name); + InitializeObjectAttributes(&object_attributes, &unicode_string, OBJ_CASE_INSENSITIVE, NULL, NULL); + + status = ZwOpenFile(&file_handle, 0, &object_attributes, &status_block, FILE_SHARE_READ | FILE_SHARE_WRITE, 0); + if (NT_SUCCESS(status)) { + status = ZwDeviceIoControlFile(file_handle, event_handle, 0, 0, &status_block, IOCTL_NDIS_QUERY_GLOBAL_STATS, &code, sizeof(code), mac, sizeof(mac)); + if (status == STATUS_PENDING) + status = ZwWaitForSingleObject(event_handle, FALSE, NULL); + if (NT_SUCCESS(status)) { + size = sizeof(mac); + ProcessMAC(mac, size); + } + ZwClose(file_handle); + } + } + ExFreePool(service_name); + ExFreePool(sub_key_value); + ZwClose(key_handle); + + if (block_count_no_mac == block_count_ && size) + AddBlock(mac, size, BLOCK_MAC); + } + ZwClose(event_handle); + +#else + HMODULE dll = LoadLibraryA(VMProtectDecryptStringA("iphlpapi.dll")); + if (!dll) + return; + + typedef ULONG (WINAPI *GET_ADAPTERS_INFO) (PIP_ADAPTER_INFO AdapterInfo, PULONG SizePointer); + GET_ADAPTERS_INFO get_adapters_info = reinterpret_cast<GET_ADAPTERS_INFO>(InternalGetProcAddress(dll, VMProtectDecryptStringA("GetAdaptersInfo"))); + + if (get_adapters_info) { + ULONG buf_len = 0; + if (ERROR_BUFFER_OVERFLOW == get_adapters_info(NULL, &buf_len)) { + uint32_t block_count_no_mac = block_count_; + const uint8_t *mac = NULL; + size_t size = 0; + uint8_t *info = new uint8_t[buf_len]; + if (ERROR_SUCCESS == get_adapters_info(reinterpret_cast<IP_ADAPTER_INFO *>(info), &buf_len)) { + for (IP_ADAPTER_INFO *adapter_info = reinterpret_cast<IP_ADAPTER_INFO *>(info); adapter_info != 0; adapter_info = adapter_info->Next) { + mac = adapter_info->Address; + size = adapter_info->AddressLength; + ProcessMAC(mac, size); + } + } + if (block_count_no_mac == block_count_ && mac && size) + AddBlock(mac, size, BLOCK_MAC); + delete [] info; + } + } + FreeLibrary(dll); +#endif +} + +void HardwareID::GetHDD() +{ +#ifdef __APPLE__ + 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); + } +#elif defined(__unix__) + std::string root_uuid; + if (FILE *mtab = setmntent("/etc/mtab", "r")) { + std::string root_fs_path; + while (struct mntent *entry = getmntent(mtab)) { + if (entry->mnt_dir[0] == '/' && entry->mnt_dir[1] == 0) { + root_fs_path = entry->mnt_fsname; + break; + } + } + endmntent(mtab); + + if (!root_fs_path.empty()) { + std::string dir_name("/dev/disk/by-uuid/"); + if (DIR *dir = opendir(dir_name.c_str())) { + while (struct dirent *entry = readdir(dir)) { + // skip "." and ".." + if (entry->d_name[0] == '.') { + if (entry->d_name[1] == 0 || (entry->d_name[1] == '.' && entry->d_name[2] == 0)) + continue; + } + + char resolved_link_path[PATH_MAX]; + std::string path = dir_name + entry->d_name; + if (realpath(path.c_str(), resolved_link_path)) { + if (strcmp(resolved_link_path, root_fs_path.c_str()) == 0) { + root_uuid = entry->d_name; + break; + } + } + } + closedir(dir); + } + } + } + if (!root_uuid.empty()) + AddBlock(root_uuid.c_str(), root_uuid.size(), BLOCK_HDD); +#elif defined(WIN_DRIVER) + wchar_t buf[MAX_PATH]; + size_t size = _countof(buf); + UNICODE_STRING unicode_string; + OBJECT_ATTRIBUTES object_attributes; + NTSTATUS status; + HANDLE handle; + IO_STATUS_BLOCK status_block; + + if (!GetRegValue(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion", L"SystemRoot", buf, &size)) + return; + + if (buf[1] == ':' && buf[2] == '\\') { + wchar_t system_drive[] = {'\\', 'D', 'o', 's', 'D', 'e', 'v', 'i', 'c', 'e', 's', '\\', buf[0], ':', '\\', 0}; + + RtlInitUnicodeString(&unicode_string, system_drive); + InitializeObjectAttributes(&object_attributes, &unicode_string, OBJ_CASE_INSENSITIVE, NULL, NULL); + status = ZwCreateFile(&handle, SYNCHRONIZE | FILE_READ_ACCESS, + &object_attributes, + &status_block, + NULL, + 0, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN, + FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0); + if (NT_SUCCESS(status)) { + RtlInitUnicodeString(&unicode_string, L"ZwQueryVolumeInformationFile"); + typedef NTSTATUS (NTAPI *QUERY_VOLUME_INFORMATION_FILE) (HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FS_INFORMATION_CLASS); + QUERY_VOLUME_INFORMATION_FILE query_volume_information_file = reinterpret_cast<QUERY_VOLUME_INFORMATION_FILE>(MmGetSystemRoutineAddress(&unicode_string)); + if (query_volume_information_file) { + ULONG size = sizeof(FILE_FS_VOLUME_INFORMATION) + MAX_PATH * sizeof(WCHAR); + FILE_FS_VOLUME_INFORMATION *information = reinterpret_cast<FILE_FS_VOLUME_INFORMATION*>(new uint8_t[size]); + status = query_volume_information_file(handle, &status_block, information, size, FileFsVolumeInformation); + if (NT_SUCCESS(status)) + AddBlock(&information->VolumeSerialNumber, sizeof(information->VolumeSerialNumber), BLOCK_HDD); + delete [] information; + } + ZwClose(handle); + } + } +#else + HMODULE dll = LoadLibraryA(VMProtectDecryptStringA("kernel32.dll")); + if (!dll) + return; + + typedef ULONG (WINAPI *GET_WINDOWS_DIRECTORY) (wchar_t *, DWORD); + GET_WINDOWS_DIRECTORY get_windows_directory = reinterpret_cast<GET_WINDOWS_DIRECTORY>(InternalGetProcAddress(dll, VMProtectDecryptStringA("GetWindowsDirectoryW"))); + typedef BOOL (WINAPI *GET_VOLUME_INFORMATION) (const wchar_t *, wchar_t *, DWORD, DWORD *, DWORD *, DWORD *, wchar_t *, DWORD); + GET_VOLUME_INFORMATION get_volume_information = reinterpret_cast<GET_VOLUME_INFORMATION>(InternalGetProcAddress(dll, VMProtectDecryptStringA("GetVolumeInformationW"))); + + if (get_windows_directory && get_volume_information) { + wchar_t buf[MAX_PATH] = {0}; + UINT ures = get_windows_directory(buf, _countof(buf)); + if (ures > 0 && buf[1] == ':' && buf[2] == '\\') { + buf[3] = 0; + DWORD volumeSerialNumber = 0; + if (get_volume_information(buf, NULL, 0, &volumeSerialNumber, NULL, NULL, NULL, 0)) { + AddBlock(&volumeSerialNumber, sizeof(volumeSerialNumber), BLOCK_HDD); + } + } + } + FreeLibrary(dll); +#endif +} + +size_t HardwareID::Copy(void *dest, size_t size) const +{ + uint32_t *p = reinterpret_cast<uint32_t *>(dest); + // need skip old methods + size_t res = std::min(static_cast<size_t>(block_count_ - start_block_), size / sizeof(uint32_t)); + for (size_t i = 0; i < res; i++) { + p[i] = blocks_->GetDWord((start_block_ + i) * sizeof(uint32_t)); + } + return res * sizeof(uint32_t); +} + +/* + Rules: + 1. if pointer to buffer is NULL, second parameter is ignored and returned size of buffer that will fit HWID (with trailing 0) + 2. if buffer is ok and the second parameters is zero, we should return zero and doesn't change the buffer + 3. if buffer is OK and the second parameter is less than we need, we should return as much bytes as we can and return the second parameter itself + and we should put 0 to the last available position at buffer + 4. if buffer is bigger that we need, we should put HWID, trailing 0 and return strlen(hwid) + 1 +*/ + +int HardwareID::GetCurrent(char *buffer, int size) +{ + if (buffer && size == 0) + return 0; // see rule #2 + + uint8_t b[MAX_BLOCKS *sizeof(uint32_t)]; + size_t hwid_size = Copy(b, sizeof(b)); + size_t need_size = Base64EncodeGetRequiredLength(hwid_size); + char *p = new char[need_size + 1]; + Base64Encode(b, hwid_size, p, need_size); // it never should return false + + size_t copy = 0; + if (buffer) { + // if nSize is less, we have to leave space for trailing zero (see rule #3) + // if nNeedSize is less, we already have this space, as we allocated nNeedSize + 1 bytes + copy = std::min(static_cast<size_t>(size - 1), need_size); + for (size_t i = 0; i < copy; i++) { + buffer[i] = p[i]; + } + buffer[copy++] = 0; + } + else { + // see rule #1 + copy = need_size + 1; + } + + delete [] p; + return static_cast<int>(copy); +} + +bool HardwareID::IsCorrect(uint8_t *p, size_t size) const +{ + if (p == 0 || size == 0 || (size & 3)) + return false; + + bool equals[4]; + bool found[4]; + for (size_t i = 0; i < 4; i++) { + equals[i] = false; + found[i] = false; + } + + size_t blocks = size / sizeof(uint32_t); + uint32_t *d = reinterpret_cast<uint32_t *>(p); + for (size_t j = 0; j < block_count_; j++) { + uint32_t id1 = blocks_->GetDWord(j * sizeof(uint32_t)); + found[id1 & 3] = true; + for (size_t i = 0; i < blocks; i++) { + uint32_t id2 = d[i]; + if (id1 == id2) { + equals[id1 & 3] = true; + break; + } + } + } + + // check CPU + if (!equals[0]) + return false; + + // check if at least 3 items are OK + size_t n = 0; + size_t c = 0; + for (size_t i = 0; i < 4; i++) { + if (found[i]) + c++; + if (equals[i]) + n++; + } + return (n == c || n >= 3); +} + +bool HardwareID::IsCorrect(CryptoContainer &cont, size_t offset, size_t size) const +{ + 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 diff --git a/runtime/hwid.h b/runtime/hwid.h new file mode 100644 index 0000000..c9d17a0 --- /dev/null +++ b/runtime/hwid.h @@ -0,0 +1,45 @@ +#ifndef HWID_H +#define HWID_H + +class CryptoContainer; + +class HardwareID +{ +public: + HardwareID(); + ~HardwareID(); + + size_t Copy(void *dest, size_t size) const; + int GetCurrent(char *buffer, int size); + bool IsCorrect(uint8_t *p, size_t s) const; + bool IsCorrect(CryptoContainer &cont, size_t offset, size_t size) const; +private: + enum { + MAX_BLOCKS = 16, + TYPE_MASK = 3 + }; + enum BlockType { + BLOCK_CPU, + BLOCK_HOST, + BLOCK_MAC, + BLOCK_HDD, + }; + uint32_t block_count_; + uint32_t start_block_; + CryptoContainer *blocks_; + + void AddBlock(const void *p, size_t size, BlockType type); + void ProcessMAC(const uint8_t *p, size_t size); + void ProcessCPU(uint8_t method); + + void GetCPU(uint8_t method); + void GetMacAddresses(); + void GetMachineName(); + void GetHDD(); + + // no copy ctr or assignment op + HardwareID(const HardwareID &); + HardwareID &operator =(const HardwareID &); +}; + +#endif
\ No newline at end of file diff --git a/runtime/licensing_manager.cc b/runtime/licensing_manager.cc new file mode 100644 index 0000000..bc1039f --- /dev/null +++ b/runtime/licensing_manager.cc @@ -0,0 +1,1135 @@ +#include "common.h" +#include "objects.h" +#include "utils.h" +#include "core.h" +#include "crypto.h" +#include "licensing_manager.h" +#include "hwid.h" +#include "loader.h" + +#if defined(__unix__) +#include <sys/time.h> +#include <curl/curl.h> +#endif + +/** + * exported functions + */ + +#ifdef VMP_GNU +EXPORT_API int WINAPI ExportedSetSerialNumber(const char *serial) __asm__ ("ExportedSetSerialNumber"); +EXPORT_API int WINAPI ExportedGetSerialNumberState() __asm__ ("ExportedGetSerialNumberState"); +EXPORT_API bool WINAPI ExportedGetSerialNumberData(VMProtectSerialNumberData *data, int size) __asm__ ("ExportedGetSerialNumberData"); +EXPORT_API int WINAPI ExportedActivateLicense(const char *code, char *serial, int size) __asm__ ("ExportedActivateLicense"); +EXPORT_API int WINAPI ExportedDeactivateLicense(const char *serial) __asm__ ("ExportedDeactivateLicense"); +EXPORT_API int WINAPI ExportedGetOfflineActivationString(const char *code, char *buf, int size) __asm__ ("ExportedGetOfflineActivationString"); +EXPORT_API int WINAPI ExportedGetOfflineDeactivationString(const char *serial, char *buf, int size) __asm__ ("ExportedGetOfflineDeactivationString"); +EXPORT_API void WINAPI ExportedDecryptBuffer(uint8_t *buffer) __asm__ ("ExportedDecryptBuffer"); +#elif defined(USE_WININET) + #include <wininet.h> +#else + #ifndef WIN_DRIVER + #include <winhttp.h> + #include <xstring> + #endif +#endif + +int WINAPI ExportedSetSerialNumber(const char *serial) +{ + LicensingManager *licensing_manager = Core::Instance()->licensing_manager(); + return licensing_manager ? licensing_manager->SetSerialNumber(serial) : SERIAL_STATE_FLAG_CORRUPTED; +} + +int WINAPI ExportedGetSerialNumberState() +{ + LicensingManager *licensing_manager = Core::Instance()->licensing_manager(); + return licensing_manager ? licensing_manager->GetSerialNumberState() : SERIAL_STATE_FLAG_CORRUPTED; +} + +bool WINAPI ExportedGetSerialNumberData(VMProtectSerialNumberData *data, int size) +{ + LicensingManager *licensing_manager = Core::Instance()->licensing_manager(); + return licensing_manager ? licensing_manager->GetSerialNumberData(data, size) : false; +} + +int WINAPI ExportedActivateLicense(const char *code, char *serial, int size) +{ + LicensingManager *licensing_manager = Core::Instance()->licensing_manager(); + return licensing_manager ? licensing_manager->ActivateLicense(code, serial, size) : ACTIVATION_NOT_AVAILABLE; +} + +int WINAPI ExportedDeactivateLicense(const char *serial) +{ + LicensingManager *licensing_manager = Core::Instance()->licensing_manager(); + return licensing_manager ? licensing_manager->DeactivateLicense(serial) : ACTIVATION_NOT_AVAILABLE; +} + +int WINAPI ExportedGetOfflineActivationString(const char *code, char *buf, int size) +{ + LicensingManager *licensing_manager = Core::Instance()->licensing_manager(); + return licensing_manager ? licensing_manager->GetOfflineActivationString(code, buf, size) : ACTIVATION_NOT_AVAILABLE; +} + +int WINAPI ExportedGetOfflineDeactivationString(const char *serial, char *buf, int size) +{ + LicensingManager *licensing_manager = Core::Instance()->licensing_manager(); + return licensing_manager ? licensing_manager->GetOfflineDeactivationString(serial, buf, size) : ACTIVATION_NOT_AVAILABLE; +} + +void WINAPI ExportedDecryptBuffer(uint8_t *buffer) +{ + LicensingManager *licensing_manager = Core::Instance()->licensing_manager(); + if (licensing_manager) + licensing_manager->DecryptBuffer(buffer); +} + +/** + * LicensingManager + */ + +#ifdef __APPLE__ + +#include "CFGregorianDateCreate.hpp" + +uint32_t GetTickCount() +{ + const int64_t one_million = 1000 * 1000; + mach_timebase_info_data_t timebase_info; + mach_timebase_info(&timebase_info); + + // mach_absolute_time() returns billionth of seconds, + // so divide by one million to get milliseconds + return static_cast<uint32_t>((mach_absolute_time() * timebase_info.numer) / (one_million * timebase_info.denom)); +} +#elif defined(WIN_DRIVER) +uint32_t GetTickCount() +{ + LARGE_INTEGER tick_count; + KeQueryTickCount(&tick_count); + return static_cast<uint32_t>(tick_count.QuadPart * KeQueryTimeIncrement() / 10000); +} +#endif +#ifdef __unix__ +unsigned long GetTickCount() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} +#endif +LicensingManager::LicensingManager(uint8_t *data, uint32_t size, uint8_t *key) + : start_(0), serial_(NULL) +{ + CriticalSection::Init(critical_section_); + session_key_ = 0 - static_cast<uint32_t>(loader_data->session_key()); + license_data_ = new CryptoContainer(data, size, key); + start_tick_count_ = GetTickCount(); + save_state(SERIAL_STATE_FLAG_INVALID); +} + +LicensingManager::~LicensingManager() +{ + delete license_data_; + delete serial_; + CriticalSection::Free(critical_section_); +} + +int LicensingManager::save_state(int new_state) +{ + if (new_state & (SERIAL_STATE_FLAG_CORRUPTED | SERIAL_STATE_FLAG_INVALID | SERIAL_STATE_FLAG_BLACKLISTED | SERIAL_STATE_FLAG_BAD_HWID)) { + product_code_ = 0; + if (serial_) { + delete serial_; + serial_ = NULL; + } + } else if (new_state & (SERIAL_STATE_FLAG_DATE_EXPIRED | SERIAL_STATE_FLAG_RUNNING_TIME_OVER | SERIAL_STATE_FLAG_MAX_BUILD_EXPIRED)) { + if (state_ == SERIAL_STATE_FLAG_INVALID) + product_code_ = 0; + } + state_ = new_state; + return state_; +} + +bool LicensingManager::CheckLicenseDataCRC() const +{ + size_t crc_pos = license_data_->GetDWord(FIELD_CRC_OFFSET * sizeof(uint32_t)); + size_t size = crc_pos + 16; + if (size != license_data_->size()) + return false; // bad key size + + // CRC check + SHA1 hash; + hash.Input(license_data_->data(), crc_pos); + const uint8_t *p = hash.Result(); + for (size_t i = crc_pos; i < size; i++) { + if (license_data_->GetByte(i) != p[i - crc_pos]) + return false; + } + + return true; +} + +int LicensingManager::SetSerialNumber(const char *serial) +{ + CriticalSection cs(critical_section_); + + save_state(SERIAL_STATE_FLAG_INVALID); + + if (!serial) + return SERIAL_STATE_FLAG_INVALID; // the key is empty + + size_t len = 0; + while (serial[len]) { + len++; + } + if (!len) + return SERIAL_STATE_FLAG_INVALID; // the key is empty + + // decode serial number from base64 + uint8_t *binary_serial = new uint8_t[len]; + if (!Base64Decode(serial, len, binary_serial, len) || len < 16) { + delete [] binary_serial; + return SERIAL_STATE_FLAG_INVALID; + } + + // check license data integrity + if (!CheckLicenseDataCRC()) { + delete [] binary_serial; + return save_state(SERIAL_STATE_FLAG_CORRUPTED); + } + + // check serial by black list + size_t black_list_size = license_data_->GetDWord(FIELD_BLACKLIST_SIZE * sizeof(uint32_t)); + if (black_list_size) { + size_t black_list_offset = license_data_->GetDWord(FIELD_BLACKLIST_OFFSET * sizeof(uint32_t)); + + SHA1 hash; + hash.Input(binary_serial, len); + const uint32_t *p = reinterpret_cast<const uint32_t *>(hash.Result()); + int min = 0; + int max = (int)black_list_size / 20 - 1; + while (min <= max) { + int i = (min + max) / 2; + bool blocked = true; + for (size_t j = 0; j < 20 / sizeof(uint32_t); j++) { + uint32_t dw = license_data_->GetDWord(black_list_offset + i * 20 + j * sizeof(uint32_t)); + if (dw == p[j]) + continue; + + if (__builtin_bswap32(dw) > __builtin_bswap32(p[j])) { + max = i - 1; + } else { + min = i + 1; + } + blocked = false; + break; + } + if (blocked) { + delete[] binary_serial; + return save_state(SERIAL_STATE_FLAG_BLACKLISTED); + } + } + } + + // decode serial number + BigNumber x(binary_serial, len); + delete [] binary_serial; + + serial_ = x.modpow(*license_data_, + license_data_->GetDWord(FIELD_PUBLIC_EXP_OFFSET * sizeof(uint32_t)), license_data_->GetDWord(FIELD_PUBLIC_EXP_SIZE * sizeof(uint32_t)), + license_data_->GetDWord(FIELD_MODULUS_OFFSET * sizeof(uint32_t)), license_data_->GetDWord(FIELD_MODULUS_SIZE * sizeof(uint32_t))); + + if (!serial_) + return SERIAL_STATE_FLAG_INVALID; + + if (serial_->GetByte(0) != 0 || serial_->GetByte(1) != 2) + return SERIAL_STATE_FLAG_INVALID; + + size_t pos; + for (pos = 2; pos < serial_->size(); pos++) { + if (!serial_->GetByte(pos)) { + pos++; + break; + } + } + if (pos == serial_->size()) + return SERIAL_STATE_FLAG_INVALID; + + start_ = pos; + return ParseSerial(NULL); +} + +uint32_t LicensingManager::GetCurrentDate() +{ + uint32_t cur_date; +#ifdef VMP_GNU + time_t rawtime; + time(&rawtime); + struct tm local_tm; + tm *timeinfo = localtime_r(&rawtime, &local_tm); + cur_date = ((timeinfo->tm_year + 1900) << 16) + (static_cast<uint8_t>(timeinfo->tm_mon + 1) << 8) + static_cast<uint8_t>(timeinfo->tm_mday); +#elif defined(WIN_DRIVER) + LARGE_INTEGER sys_time; + LARGE_INTEGER local_time; + TIME_FIELDS time_fields; + + KeQuerySystemTime(&sys_time); + ExSystemTimeToLocalTime(&sys_time, &local_time); + RtlTimeToTimeFields(&local_time, &time_fields); + cur_date = (time_fields.Year << 16) + (static_cast<uint8_t>(time_fields.Month) << 8) + static_cast<uint8_t>(time_fields.Day); +#else + typedef struct _KSYSTEM_TIME + { + ULONG LowPart; + LONG High1Time; + LONG High2Time; + } KSYSTEM_TIME, *PKSYSTEM_TIME; + + typedef struct _KUSER_SHARED_DATA + { + ULONG TickCountLowDeprecated; + ULONG TickCountMultiplier; + KSYSTEM_TIME InterruptTime; + KSYSTEM_TIME SystemTime; + KSYSTEM_TIME TimeZoneBias; + //... + } KUSER_SHARED_DATA, *PKUSER_SHARED_DATA; + + PKUSER_SHARED_DATA user_shared_data = reinterpret_cast<PKUSER_SHARED_DATA>(0x7FFE0000); + LARGE_INTEGER sys_time, time_zone_bias, local_time; + while (true) { + sys_time.HighPart = user_shared_data->SystemTime.High1Time; + sys_time.LowPart = user_shared_data->SystemTime.LowPart; + if (sys_time.HighPart == user_shared_data->SystemTime.High2Time) + break; + } + while (true) { + time_zone_bias.HighPart = user_shared_data->TimeZoneBias.High1Time; + time_zone_bias.LowPart = user_shared_data->TimeZoneBias.LowPart; + if (time_zone_bias.HighPart == user_shared_data->TimeZoneBias.High2Time) + break; + } + local_time.QuadPart = sys_time.QuadPart - time_zone_bias.QuadPart; + + __int64 total_days_since_1601 = local_time.QuadPart / 864000000000ull; + uint32_t number_of_400s = static_cast<uint32_t>(total_days_since_1601 / 146097); + total_days_since_1601 -= number_of_400s * 146097; + uint32_t number_of_100s = static_cast<uint32_t>((total_days_since_1601 * 100 + 75) / 3652425); + total_days_since_1601 -= number_of_100s * 36524; + uint32_t number_of_4s = static_cast<uint32_t>(total_days_since_1601 / 1461); + total_days_since_1601 -= number_of_4s * 1461; + uint16_t year = static_cast<uint16_t>((total_days_since_1601 * 100 + 75) / 36525); + total_days_since_1601 -= 365 * year; + year = static_cast<uint16_t>((number_of_400s * 400) + (number_of_100s * 100) + (number_of_4s * 4) + year + 1601); + uint16_t day = static_cast<uint16_t>(total_days_since_1601 + 1); + int days_in_month[] = {31, ((year % 400 == 0) || (year % 100 != 0) && (year % 4 == 0)) ? 29 : 28, + 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + uint8_t month = 1; + for (size_t i = 0; i < _countof(days_in_month); i++) { + if (day > days_in_month[i]) { + ++month; + day -= days_in_month[i]; + } else + break; + } + assert(month <= 12); + cur_date = (year << 16) + (static_cast<uint8_t>(month) << 8) + static_cast<uint8_t>(day); +#endif + + return std::max(cur_date, loader_data->server_date()); +} + +int LicensingManager::ParseSerial(VMProtectSerialNumberData *data) +{ + if (!serial_) + return SERIAL_STATE_FLAG_INVALID; + + int new_state = state_ & (SERIAL_STATE_FLAG_MAX_BUILD_EXPIRED | SERIAL_STATE_FLAG_DATE_EXPIRED | SERIAL_STATE_FLAG_RUNNING_TIME_OVER); + size_t pos = start_; + while (pos < serial_->size()) { + uint8_t b = serial_->GetByte(pos++); + uint8_t s; + switch (b) { + case SERIAL_CHUNK_VERSION: + if (serial_->GetByte(pos) != 1) + return save_state(SERIAL_STATE_FLAG_INVALID); + pos += 1; + break; + case SERIAL_CHUNK_EXP_DATE: + uint32_t exp_date; + exp_date = serial_->GetDWord(pos); + if ((new_state & SERIAL_STATE_FLAG_DATE_EXPIRED) == 0) { + if (license_data_->GetDWord(FIELD_BUILD_DATE * sizeof(uint32_t)) > exp_date || GetCurrentDate() > exp_date) + new_state |= SERIAL_STATE_FLAG_DATE_EXPIRED; + } + if (data) { + data->dtExpire.wYear = exp_date >> 16; + data->dtExpire.bMonth = static_cast<uint8_t>(exp_date >> 8); + data->dtExpire.bDay = static_cast<uint8_t>(exp_date); + } + pos += 4; + break; + case SERIAL_CHUNK_RUNNING_TIME_LIMIT: + s = serial_->GetByte(pos); + if ((new_state & SERIAL_STATE_FLAG_RUNNING_TIME_OVER) == 0) { + uint32_t tick_count = GetTickCount(); + size_t cur_time = (tick_count - start_tick_count_) / 1000 / 60; + if (cur_time > s) + new_state |= SERIAL_STATE_FLAG_RUNNING_TIME_OVER; + } + if (data) + data->bRunningTime = s; + pos += 1; + break; + case SERIAL_CHUNK_PRODUCT_CODE: + if (state_ == SERIAL_STATE_FLAG_INVALID) + product_code_ = serial_->GetQWord(pos); + pos += 8; + break; + case SERIAL_CHUNK_MAX_BUILD: + uint32_t max_build_date; + max_build_date = serial_->GetDWord(pos); + if ((new_state & SERIAL_STATE_FLAG_MAX_BUILD_EXPIRED) == 0) { + if (license_data_->GetDWord(FIELD_BUILD_DATE * sizeof(uint32_t)) > max_build_date) + new_state |= SERIAL_STATE_FLAG_MAX_BUILD_EXPIRED; + } + if (data) { + data->dtMaxBuild.wYear = max_build_date >> 16; + data->dtMaxBuild.bMonth = static_cast<uint8_t>(max_build_date >> 8); + data->dtMaxBuild.bDay = static_cast<uint8_t>(max_build_date); + } + pos += 4; + break; + case SERIAL_CHUNK_USER_NAME: + s = serial_->GetByte(pos++); + if (data) + serial_->UTF8ToUnicode(pos, s, data->wUserName, _countof(data->wUserName)); + pos += s; + break; + case SERIAL_CHUNK_EMAIL: + s = serial_->GetByte(pos++); + if (data) + serial_->UTF8ToUnicode(pos, s, data->wEMail, _countof(data->wEMail)); + pos += s; + break; + case SERIAL_CHUNK_HWID: + s = serial_->GetByte(pos++); + if (state_ == SERIAL_STATE_FLAG_INVALID) { + HardwareID *hardware_id = Core::Instance()->hardware_id(); + if (!hardware_id->IsCorrect(*serial_, pos, s)) + return save_state(SERIAL_STATE_FLAG_BAD_HWID); + } + pos += s; + break; + case SERIAL_CHUNK_USER_DATA: + s = serial_->GetByte(pos++); + if (data) { + data->nUserDataLength = static_cast<uint8_t>(s); + for (size_t i = 0; i < s; i++) { + data->bUserData[i] = serial_->GetByte(pos + i); + } + } + pos += s; + break; + case SERIAL_CHUNK_END: + if (pos + 4 > serial_->size()) + return save_state(SERIAL_STATE_FLAG_INVALID); + + if (state_ == SERIAL_STATE_FLAG_INVALID) { + // calc hash without last chunk + SHA1 hash; + hash.Input(*serial_, start_, pos - start_ - 1); + + // check CRC + const uint8_t *p = hash.Result(); + for (size_t i = 0; i < 4; i++) { + if (serial_->GetByte(pos + i) != p[3 - i]) + return save_state(SERIAL_STATE_FLAG_INVALID); + } + } + + return save_state(new_state); + } + } + + // SERIAL_CHUNK_END not found + return save_state(SERIAL_STATE_FLAG_INVALID); +} + +int LicensingManager::GetSerialNumberState() +{ + CriticalSection cs(critical_section_); + + if (state_ & (SERIAL_STATE_FLAG_CORRUPTED | SERIAL_STATE_FLAG_INVALID | SERIAL_STATE_FLAG_BLACKLISTED | SERIAL_STATE_FLAG_BAD_HWID)) + return state_; // no reasons to continue + + return ParseSerial(NULL); +} + +bool LicensingManager::GetSerialNumberData(VMProtectSerialNumberData *data, int size) +{ + if (!data || size != sizeof(VMProtectSerialNumberData)) + return false; // bad input + + CriticalSection cs(critical_section_); + + if (state_ == SERIAL_STATE_FLAG_CORRUPTED) + return false; + + // clean memory + uint8_t *p = reinterpret_cast<uint8_t *>(data); + for (int i = 0; i < size; i++) { + p[i] = 0; + } + + data->nState = (state_ & (SERIAL_STATE_FLAG_INVALID | SERIAL_STATE_FLAG_BLACKLISTED | SERIAL_STATE_FLAG_BAD_HWID)) ? state_ : ParseSerial(data); + return true; +} + +int LicensingManager::ActivateLicense(const char *code, char *serial, int size) const +{ +#ifdef WIN_DRIVER + return ACTIVATION_NOT_AVAILABLE; +#else + if (!CheckLicenseDataCRC()) + return ACTIVATION_CORRUPTED; + + ActivationRequest request; + int res = request.Process(*license_data_, code, false); + if (res == ACTIVATION_OK) { + int need = static_cast<int>(strlen(request.serial())); + if (need > size - 1) + return ACTIVATION_SMALL_BUFFER; + strncpy_s(serial, size, request.serial(), need); + } + return res; +#endif +} + +int LicensingManager::DeactivateLicense(const char *serial) const +{ +#ifdef WIN_DRIVER + return ACTIVATION_NOT_AVAILABLE; +#else + if (!CheckLicenseDataCRC()) + return ACTIVATION_CORRUPTED; + + DeactivationRequest request; + return request.Process(*license_data_, serial, false); +#endif +} + +int LicensingManager::GetOfflineActivationString(const char *code, char *buf, int size) const +{ +#ifdef WIN_DRIVER + return ACTIVATION_NOT_AVAILABLE; +#else + if (!buf || size <= 0) + return ACTIVATION_SMALL_BUFFER; + + if (!CheckLicenseDataCRC()) + return ACTIVATION_CORRUPTED; + + ActivationRequest request; + int res = request.Process(*license_data_, code, true); + if (res == ACTIVATION_OK) { + int need = static_cast<int>(strlen(request.url())); + if (need > size - 1) + return ACTIVATION_SMALL_BUFFER; + strncpy_s(buf, size, request.url(), need); + } + return res; +#endif +} + +int LicensingManager::GetOfflineDeactivationString(const char *serial, char *buf, int size) const +{ +#ifdef WIN_DRIVER + return ACTIVATION_NOT_AVAILABLE; +#else + if (!buf || size <= 0) + return ACTIVATION_SMALL_BUFFER; + + if (!CheckLicenseDataCRC()) + return ACTIVATION_CORRUPTED; + + DeactivationRequest request; + int res = request.Process(*license_data_, serial, true); + if (res == ACTIVATION_OK) { + int need = static_cast<int>(strlen(request.url())); + if (need > size - 1) + return ACTIVATION_SMALL_BUFFER; + strncpy_s(buf, size, request.url(), need); + } + return res; +#endif +} + +void LicensingManager::DecryptBuffer(uint8_t *buffer) +{ + uint32_t key0 = static_cast<uint32_t>(product_code_); + uint32_t key1 = static_cast<uint32_t>(product_code_ >> 32) + session_key_; + uint32_t *p = reinterpret_cast<uint32_t*>(buffer); + + p[0] = _rotl32((p[0] + session_key_) ^ key0, 7) + key1; + p[1] = _rotl32((p[1] + session_key_) ^ key0, 11) + key1; + p[2] = _rotl32((p[2] + session_key_) ^ key0, 17) + key1; + p[3] = _rotl32((p[3] + session_key_) ^ key0, 23) + key1; + + if (p[0] + p[1] + p[2] + p[3] != session_key_ * 4) { + const VMP_CHAR *message; +#ifdef VMP_GNU + message = VMProtectDecryptStringA(MESSAGE_SERIAL_NUMBER_REQUIRED_STR); +#else + message = VMProtectDecryptStringW(MESSAGE_SERIAL_NUMBER_REQUIRED_STR); +#endif + if (message[0]) + ShowMessage(message); + +#if defined(VMP_GNU) + exit(0xDEADC0DE); +#elif defined(WIN_DRIVER) + DbgBreakPointWithStatus(0xDEADC0DE); +#else + TerminateProcess(GetCurrentProcess(), 0xDEADC0DE); +#endif + } +} + +#ifndef WIN_DRIVER + +/** + * BaseRequest + */ + +BaseRequest::BaseRequest() + : response_(NULL) +{ + url_[0] = 0; +} + +BaseRequest::~BaseRequest() +{ + delete [] response_; +} + +bool BaseRequest::BuildUrl(const CryptoContainer &license_data) +{ + size_t url_size = license_data.GetDWord(FIELD_ACTIVATION_URL_SIZE * sizeof(uint32_t)); + if (!url_size) + return false; + + size_t url_offset = license_data.GetDWord(FIELD_ACTIVATION_URL_OFFSET * sizeof(uint32_t)); + for (size_t i = 0; i < url_size; i++) { + url_[i] = license_data.GetByte(url_offset + i); + } + if (url_[url_size] != '/') + url_[url_size++] = '/'; + url_[url_size] = 0; + return true; +} + +#ifdef __unix__ +static size_t curl_write_data(void *ptr, size_t size, size_t nmemb, void *stream) +{ + size_t written = size * nmemb; + + std::string *dest = (std::string *)stream; + *dest += std::string((char *)ptr, written); + return written; +} +static size_t curl_header(void *ptr, size_t size, size_t nmemb, void *stream) +{ + size_t written = size * nmemb; + + if(strncmp((char*)ptr, "Date: ", 6) == 0) + { + *((time_t *)stream) = curl_getdate((char *)ptr + 6, NULL); + } + return written; +} +#endif + +bool BaseRequest::Send() +{ + if (response_) { + delete [] response_; + response_ = NULL; + } + +#ifdef __APPLE__ + CFStringRef str_ref = CFStringCreateWithCString(NULL, url_, kCFStringEncodingMacRoman); + CFURLRef url_ref = CFURLCreateWithString(kCFAllocatorDefault, str_ref, NULL); + CFHTTPMessageRef req_ref = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("GET"), url_ref, kCFHTTPVersion1_1); + CFReadStreamRef stream_ref = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, req_ref); + + CFReadStreamOpen(stream_ref); + int current; + int size = 8096; + response_ = new char[size]; + CFIndex read_size; + for (current = 0; current < size; current += read_size) { + read_size = CFReadStreamRead(stream_ref, reinterpret_cast<uint8_t *>(response_ + current), size - current); + if (read_size < 0) + break; // error + if (!read_size) + break; // end of data + } + if (current < size) + response_[current] = 0; + bool res = current > 0 && current < size; + + CFHTTPMessageRef resp = (CFHTTPMessageRef)CFReadStreamCopyProperty(stream_ref, kCFStreamPropertyHTTPResponseHeader); + if(resp) + { + CFStringRef dateHeaderRef = CFHTTPMessageCopyHeaderFieldValue(resp, CFSTR("Date")); + if (dateHeaderRef != NULL) + { + CFGregorianDate gdate; + CFIndex count = _CFGregorianDateCreateWithString(kCFAllocatorDefault, dateHeaderRef, &gdate, NULL); + if (count != 0) + loader_data->set_server_date((gdate.year << 16) + (static_cast<uint8_t>(gdate.month) << 8) + static_cast<uint8_t>(gdate.day)); + CFRelease(dateHeaderRef); + } + CFRelease(resp); + } + CFReadStreamClose(stream_ref); + + CFRelease(stream_ref); + CFRelease(req_ref); + CFRelease(url_ref); + CFRelease(str_ref); + + return res; +#elif defined(__unix__) + CURL *curl = curl_easy_init(); + if (curl) { + curl_easy_setopt(curl, CURLOPT_URL, url_); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_data); + curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_header); + std::string dest; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &dest); + time_t file_time = (time_t)-1; + curl_easy_setopt(curl, CURLOPT_HEADERDATA, &file_time); + CURLcode c = curl_easy_perform(curl); + if (c == CURLE_OK) { + response_ = strdup(dest.c_str()); + if (file_time != (time_t)-1) { + struct tm local_tm; + tm *t = localtime_r(&file_time, &local_tm); + if (t) + loader_data->set_server_date(((1900 + t->tm_year) << 16) + (static_cast<uint8_t>(t->tm_mon + 1) << 8) + static_cast<uint8_t>(t->tm_mday)); + } + } + curl_easy_cleanup(curl); + return (c == CURLE_OK); + } + return false; +#else + HMODULE dll = LoadLibraryA(VMProtectDecryptStringA("winhttp.dll")); + if (!dll) + return false; + + typedef HINTERNET (WINAPI *HTTP_OPEN)(LPCWSTR lpszAgent, DWORD dwAccessType, LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags); + typedef BOOL (WINAPI *HTTP_CLOSE_HANDLE)(HINTERNET hInternet); + typedef BOOL (WINAPI *HTTP_READ_DATA)(HINTERNET hFile, LPVOID lpBuffer, DWORD dwNumberOfBytesToRead, LPDWORD lpdwNumberOfBytesRead); + typedef BOOL (WINAPI *HTTP_CRACK_URL)(LPCWSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags, LPURL_COMPONENTS lpUrlComponents); + typedef HINTERNET (WINAPI *HTTP_CONNECT)(HINTERNET hInternet, LPCWSTR lpszServerName, INTERNET_PORT nServerPort, DWORD dwReserved); + typedef BOOL (WINAPI *HTTP_SETCREDENTIALS)(HINTERNET hRequest, DWORD AuthTargets, DWORD AuthScheme, LPCWSTR pszUserName, LPCWSTR pszPassword, LPVOID pAuthParams); + typedef HINTERNET (WINAPI *HTTP_OPEN_REQUEST)(HINTERNET hConnect, LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion, LPCWSTR lpszReferer, LPCWSTR *lplpszAcceptTypes, DWORD dwFlags); + typedef BOOL (WINAPI *HTTP_SEND_REQUEST)(HINTERNET hRequest, LPCWSTR lpszHeaders, DWORD dwHeadersLength, LPVOID lpOptional, DWORD dwOptionalLength, DWORD dwTotalLength, DWORD_PTR dwContext); + typedef BOOL (WINAPI *HTTP_RECEIVE_RESPONSE)(HINTERNET hRequest, LPVOID lpReserved); + typedef BOOL (WINAPI *HTTP_SET_OPTION)(HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, DWORD dwBufferLength); + typedef BOOL (WINAPI *HTTP_GET_IE_PROXY_CONFIG)(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *pProxyConfig); + typedef BOOL(WINAPI *HTTP_QUERY_HEADERS)(HINTERNET hRequest, DWORD dwInfoLevel, LPCWSTR pwszName, LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex); + + HTTP_OPEN http_open = reinterpret_cast<HTTP_OPEN>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpOpen"))); + HTTP_READ_DATA http_read_data = reinterpret_cast<HTTP_READ_DATA>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpReadData"))); + HTTP_CLOSE_HANDLE http_close_handle = reinterpret_cast<HTTP_CLOSE_HANDLE>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpCloseHandle"))); + HTTP_CRACK_URL http_crack_url = reinterpret_cast<HTTP_CRACK_URL>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpCrackUrl"))); + HTTP_CONNECT http_connect = reinterpret_cast<HTTP_CONNECT>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpConnect"))); + HTTP_SETCREDENTIALS http_setcredentials = reinterpret_cast<HTTP_SETCREDENTIALS>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpSetCredentials"))); + HTTP_OPEN_REQUEST http_open_request = reinterpret_cast<HTTP_OPEN_REQUEST>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpOpenRequest"))); + HTTP_SEND_REQUEST http_send_request = reinterpret_cast<HTTP_SEND_REQUEST>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpSendRequest"))); + HTTP_RECEIVE_RESPONSE http_receive_response = reinterpret_cast<HTTP_RECEIVE_RESPONSE>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpReceiveResponse"))); + HTTP_SET_OPTION http_set_option = reinterpret_cast<HTTP_SET_OPTION>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpSetOption"))); + HTTP_GET_IE_PROXY_CONFIG http_get_ie_proxy_config = reinterpret_cast<HTTP_GET_IE_PROXY_CONFIG>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpGetIEProxyConfigForCurrentUser"))); + HTTP_QUERY_HEADERS http_query_headers = reinterpret_cast<HTTP_QUERY_HEADERS>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpQueryHeaders"))); + + bool res = false; + if (http_open + && http_read_data + && http_close_handle + && http_crack_url + && http_connect + && http_setcredentials + && http_open_request + && http_send_request + && http_receive_response + && http_set_option + && http_query_headers) { + WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ie_proxy_config = WINHTTP_CURRENT_USER_IE_PROXY_CONFIG(); + if (http_get_ie_proxy_config) + http_get_ie_proxy_config(&ie_proxy_config); + // We are not using WPAD directly, it is buggy (OLE actively used and may hung). + DWORD dwAccessType = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY; // default: settings from global registry, 8.1+ deprecated. +#ifdef _WIN64 + PEB64 *peb = reinterpret_cast<PEB64 *>(__readgsqword(0x60)); +#else + PEB32 *peb = reinterpret_cast<PEB32 *>(__readfsdword(0x30)); +#endif + uint16_t os_build_number = peb->OSBuildNumber; + if (os_build_number >= WINDOWS_8_1) + dwAccessType = 4; // WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY - 8.1+: smart from user IE config and/or global registry + + if (ie_proxy_config.lpszProxy) + dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; // IE manual proxy setup + HINTERNET inet = http_open(VMProtectDecryptStringW(L"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"), dwAccessType, ie_proxy_config.lpszProxy, ie_proxy_config.lpszProxyBypass, 0); + if (inet) { + URL_COMPONENTS components = URL_COMPONENTS(); + + components.dwStructSize = sizeof(components); +#define INTERNET_MAX_HOST_NAME_LENGTH 256 +#define INTERNET_MAX_USER_NAME_LENGTH 128 +#define INTERNET_MAX_PASSWORD_LENGTH 128 +#define INTERNET_MAX_PATH_LENGTH 2048 + wchar_t url_host[INTERNET_MAX_HOST_NAME_LENGTH]; + wchar_t url_path[INTERNET_MAX_PATH_LENGTH]; + wchar_t url_user[INTERNET_MAX_USER_NAME_LENGTH]; + wchar_t url_password[INTERNET_MAX_PASSWORD_LENGTH]; + components.lpszHostName = url_host; + components.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH; + components.lpszUserName = url_user; + components.dwUserNameLength = INTERNET_MAX_USER_NAME_LENGTH; + components.lpszPassword = url_password; + components.dwPasswordLength = INTERNET_MAX_PASSWORD_LENGTH; + components.lpszUrlPath = url_path; + components.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH; + http_crack_url(std::wstring(url_, url_ + strlen(url_)).c_str(), 0, 0, &components); + + HINTERNET h = 0; + HINTERNET connect = http_connect(inet, components.lpszHostName, components.nPort, 0); + if (connect) { + h = http_open_request(connect, L"GET", components.lpszUrlPath, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_BYPASS_PROXY_CACHE | ( + (components.nScheme == INTERNET_SCHEME_HTTPS) ? WINHTTP_FLAG_SECURE : 0 + )); + if (h) { + //TODO: internet_setcredentials if need + if (components.nScheme == INTERNET_SCHEME_HTTPS) { + DWORD data = SECURITY_FLAG_IGNORE_UNKNOWN_CA + | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID + | SECURITY_FLAG_IGNORE_CERT_CN_INVALID + /*| SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE*/; + http_set_option(h, WINHTTP_OPTION_SECURITY_FLAGS, &data, sizeof(data)); + } + if (!http_send_request(h, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, NULL) || !http_receive_response( h, NULL)) { + http_close_handle(h); + h = 0; + } + } + } + + if (h) { + DWORD current; + DWORD size = 8096; + response_ = new char[size]; + DWORD read_size; + for (current = 0; current < size; current += read_size) { + if (http_read_data(h, response_ + current, size - current, &read_size) != TRUE) + break; // error + if (!read_size) + break; // end of data + } + if (current < size) + response_[current] = 0; + res = current > 0 && current < size; + SYSTEMTIME dtBuf; + DWORD dtBufLength = sizeof(dtBuf); + if(http_query_headers(h, WINHTTP_QUERY_DATE | WINHTTP_QUERY_FLAG_SYSTEMTIME, WINHTTP_HEADER_NAME_BY_INDEX, &dtBuf, &dtBufLength, WINHTTP_NO_HEADER_INDEX)) { + FILETIME ft; + SystemTimeToFileTime(&dtBuf, &ft); + FileTimeToSystemTime(&ft, &dtBuf); + loader_data->set_server_date((dtBuf.wYear << 16) + (static_cast<uint8_t>(dtBuf.wMonth) << 8) + static_cast<uint8_t>(dtBuf.wDay)); + } + http_close_handle(h); + } + if (connect) + http_close_handle(connect); + http_close_handle(inet); + } + + if (ie_proxy_config.lpszAutoConfigUrl) + GlobalFree(ie_proxy_config.lpszAutoConfigUrl); + if (ie_proxy_config.lpszProxy) + GlobalFree(ie_proxy_config.lpszProxy); + if (ie_proxy_config.lpszProxyBypass) + GlobalFree(ie_proxy_config.lpszProxyBypass); + } + FreeLibrary(dll); + return res; +#endif +} + +void BaseRequest::AppendUrlParam(const char *param, const char *value) +{ + AppendUrl(param, false); + AppendUrl(value, true); +} + +void BaseRequest::AppendUrl(const char *str, bool escape) +{ + size_t pos = 0; + while (url_[pos]) { + pos++; + } + + size_t size = _countof(url_); + if (escape) { + while (*str && pos < size - 1 - 3) + { + uint8_t c = *str; + if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') { + url_[pos++] = c; + } else if (c == ' ') { + url_[pos++] = '+'; + } else { + const char *hex = "0123456789abcdef"; + url_[pos++] = '%'; + url_[pos++] = hex[c >> 4]; + url_[pos++] = hex[c & 0x0f]; + } + str++; + } + } else { + while (*str && pos < size) { + url_[pos++] = *str; + str++; + } + } + url_[pos] = 0; +} + +void BaseRequest::EncodeUrl() +{ + char buf[2048]; + strcpy_s(buf, url_); + size_t url_size = sizeof(url_); + Base64Encode(reinterpret_cast<const uint8_t *>(buf), strlen(buf), url_, url_size); + url_[url_size] = 0; +} + +/** + * ActivationRequest + */ + +ActivationRequest::ActivationRequest() + : BaseRequest(), serial_(NULL) +{ + +} + +bool ActivationRequest::VerifyCode(const char *code) const +{ + if (!code || !code[0]) + return false; + + static const char *alphabet = "0123456789abcdefghijklmnopqrstuvwxyz-"; + for (const char *p = code; *p; p++) { + if (!strchr(alphabet, tolower(*p))) + return false; + if (p - code > 32) + return false; // too long + } + return true; +} + +bool ActivationRequest::BuildUrl(const CryptoContainer &license_data, const char *code, bool offline) +{ + if (!offline) { + if (!BaseRequest::BuildUrl(license_data)) + return false; + } + + // hwid -> base64 + char str_hwid[100]; + { + uint8_t hwid[16 * sizeof(uint32_t)]; // HardwareID::MAX_BLOCKS + + size_t hwid_size = Core::Instance()->hardware_id()->Copy(hwid, sizeof(hwid)); + size_t dest_len = sizeof(str_hwid); + Base64Encode(hwid, hwid_size, str_hwid, dest_len); + str_hwid[dest_len] = 0; + } + + // hash -> base64 + char str_hash[64]; + { + SHA1 sha; + sha.Input(license_data, license_data.GetDWord(FIELD_MODULUS_OFFSET * sizeof(uint32_t)), license_data.GetDWord(FIELD_MODULUS_SIZE * sizeof(uint32_t))); + size_t dest_len = sizeof(str_hash); + Base64Encode(sha.Result(), 20, str_hash, dest_len); + str_hash[dest_len] = 0; + } + + // build url + if (offline) { + char str[] = {'t', 'y', 'p', 'e', '=', 'a', 'c', 't', 'i', 'v', 'a', 't', 'i', 'o', 'n', '&', 'c', 'o', 'd', 'e', '=', 0}; + AppendUrlParam(str, code); + } else { + char str[] = {'a', 'c', 't', 'i', 'v', 'a', 't', 'i', 'o', 'n', '.', 'p', 'h', 'p', '?', 'c', 'o', 'd', 'e', '=', 0}; + AppendUrlParam(str, code); + } + { + char str[] = {'&', 'h', 'w', 'i', 'd', '=', 0}; + AppendUrlParam(str, str_hwid); + } + { + char str[] = {'&', 'h', 'a', 's', 'h', '=', 0}; + AppendUrlParam(str, str_hash); + } + + if (offline) + EncodeUrl(); + + return true; +} + +int ActivationRequest::Process(const CryptoContainer &license_data, const char *code, bool offline) +{ + if (!VerifyCode(code)) + return ACTIVATION_BAD_CODE; + + if (!BuildUrl(license_data, code, offline)) + return ACTIVATION_NOT_AVAILABLE; + + if (offline) + return ACTIVATION_OK; + + if (!Send()) + return ACTIVATION_NO_CONNECTION; + + const char *res = response(); + if (!res || !res[0]) + return ACTIVATION_BAD_REPLY; + + // possible answers: OK, BAD, BANNED, USED, EXPIRED + // if OK - see the serial number below + + if (res[0] == 'B' && res[1] == 'A' && res[2] == 'D' && res[3] == 0) + return ACTIVATION_BAD_CODE; + + if (res[0] == 'B' && res[1] == 'A' && res[2] == 'N' && res[3] == 'N' && res[4] == 'E' && res[5] == 'D' && res[6] == 0) + return ACTIVATION_BANNED; + + if (res[0] == 'U' && res[1] == 'S' && res[2] == 'E' && res[3] == 'D' && res[4] == 0) + return ACTIVATION_ALREADY_USED; + + if (res[0] == 'E' && res[1] == 'X' && res[2] == 'P' && res[3] == 'I' && res[4] == 'R' && res[5] == 'E' && res[6] == 'D' && res[7] == 0) + return ACTIVATION_EXPIRED; + + const char *endl = strchr(res, '\n'); + if (!endl) + return ACTIVATION_BAD_REPLY; + + if (endl - res != 2) + return ACTIVATION_BAD_REPLY; + + if (res[0] != 'O' || res[1] != 'K') + return ACTIVATION_BAD_REPLY; + + size_t len = strlen(res + 3); + if (len < 64) + return ACTIVATION_BAD_REPLY; + + serial_ = res + 3; + return ACTIVATION_OK; +} + +/** + * DeactivationRequest + */ + +bool DeactivationRequest::VerifySerial(const char *serial) const +{ + if (!serial || !serial[0]) + return false; + + return true; +} + + bool DeactivationRequest::BuildUrl(const CryptoContainer &license_data, const char *serial, bool offline) +{ + if (!offline) { + if (!BaseRequest::BuildUrl(license_data)) + return false; + } + + size_t code_len = strlen(serial); + size_t len = code_len; + uint8_t *p = new uint8_t[len]; + if (!Base64Decode(serial, code_len, p, len)) { + delete [] p; + return false; + } + + // get binary hash + char str_hash[64]; + { + SHA1 sha; + sha.Input(p, len); + size_t dst_len = sizeof(str_hash); + Base64Encode(sha.Result(), 20, str_hash, dst_len); + str_hash[dst_len] = 0; + } + delete [] p; + + if (offline) { + char str[] = { 't', 'y', 'p', 'e', '=', 'd', 'e', 'a', 'c', 't', 'i', 'v', 'a', 't', 'i', 'o', 'n', '&', 'h', 'a', 's', 'h', '=', 0 }; + AppendUrlParam(str, str_hash); + } + else { + char str[] = { 'd', 'e', 'a', 'c', 't', 'i', 'v', 'a', 't', 'i', 'o', 'n', '.', 'p', 'h', 'p', '?', 'h', 'a', 's', 'h', '=', 0 }; + AppendUrlParam(str, str_hash); + } + + if (offline) + EncodeUrl(); + + return true; +} + +int DeactivationRequest::Process(const CryptoContainer &license_data, const char *serial, bool offline) +{ + if (!VerifySerial(serial)) + return ACTIVATION_BAD_CODE; + + if (!BuildUrl(license_data, serial, offline)) + return ACTIVATION_NOT_AVAILABLE; + + if (offline) + return ACTIVATION_OK; + + if (!Send()) + return ACTIVATION_NO_CONNECTION; + + const char *res = response(); + if (!res || !res[0]) + return ACTIVATION_BAD_REPLY; + + if (res[0] == 'O' && res[1] == 'K' && res[2] == 0) + return ACTIVATION_OK; + + if (res[0] == 'E' && res[1] == 'R' && res[2] == 'R' && res[3] == 'O' && res[4] == 'R' && res[5] == 0) + return ACTIVATION_CORRUPTED; + + if (res[0] == 'U' && res[1] == 'N' && res[2] == 'K' && res[3] == 'N' && res[4] == 'O' && res[5] == 'W' && res[6] == 'N' && res[7] == 0) + return ACTIVATION_SERIAL_UNKNOWN; + + return ACTIVATION_BAD_REPLY; +}; + +#endif
\ No newline at end of file diff --git a/runtime/licensing_manager.h b/runtime/licensing_manager.h new file mode 100644 index 0000000..2296efd --- /dev/null +++ b/runtime/licensing_manager.h @@ -0,0 +1,100 @@ +#ifndef LICENSING_MANAGER_H +#define LICENSING_MANAGER_H + +class CryptoContainer; + +class LicensingManager +{ +public: + LicensingManager(uint8_t *data, uint32_t size, uint8_t *key); + ~LicensingManager(); + int SetSerialNumber(const char *serial); + int GetSerialNumberState(); + bool GetSerialNumberData(VMProtectSerialNumberData *data, int size); + int ActivateLicense(const char *code, char *serial, int size) const; + int DeactivateLicense(const char *serial) const; + int GetOfflineActivationString(const char *code, char *buf, int size) const; + int GetOfflineDeactivationString(const char *serial, char *buf, int size) const; + void DecryptBuffer(uint8_t *buffer); + static uint32_t GetCurrentDate(); +private: + enum ChunkType + { + SERIAL_CHUNK_VERSION = 0x01, // 1 byte of data - version + SERIAL_CHUNK_USER_NAME = 0x02, // 1 + N bytes - length + N bytes of customer's name (without enging \0). + SERIAL_CHUNK_EMAIL = 0x03, // 1 + N bytes - length + N bytes of customer's email (without ending \0). + SERIAL_CHUNK_HWID = 0x04, // 1 + N bytes - length + N bytes of hardware id (N % 4 == 0) + SERIAL_CHUNK_EXP_DATE = 0x05, // 4 bytes - (year << 16) + (month << 8) + (day) + SERIAL_CHUNK_RUNNING_TIME_LIMIT = 0x06, // 1 byte - number of minutes + SERIAL_CHUNK_PRODUCT_CODE = 0x07, // 8 bytes - used for decrypting some parts of exe-file + SERIAL_CHUNK_USER_DATA = 0x08, // 1 + N bytes - length + N bytes of user data + SERIAL_CHUNK_MAX_BUILD = 0x09, // 4 bytes - (year << 16) + (month << 8) + (day) + SERIAL_CHUNK_END = 0xFF // 4 bytes - checksum: the first four bytes of sha-1 hash from the data before that chunk + }; + + int save_state(int state); + int ParseSerial(VMProtectSerialNumberData *data); + bool CheckLicenseDataCRC() const; + bool SendRequest(char *url, char *response, size_t size) const; + + CryptoContainer *license_data_; + int state_; + uint32_t start_tick_count_; + size_t start_; + CryptoContainer *serial_; + uint64_t product_code_; + uint32_t session_key_; + CRITICAL_SECTION critical_section_; + + // no copy ctr or assignment op + LicensingManager(const LicensingManager &); + LicensingManager &operator =(const LicensingManager &); +}; + +#ifndef WIN_DRIVER +class BaseRequest +{ +public: + BaseRequest(); + virtual ~BaseRequest(); + bool Send(); + const char *response() const { return response_; } + const char *url() const { return url_; } +protected: + bool BuildUrl(const CryptoContainer &license_data); + void EncodeUrl(); + void AppendUrlParam(const char *param, const char *value); +private: + void AppendUrl(const char *str, bool escape); + char url_[2048]; + char *response_; + + // no copy ctr or assignment op + BaseRequest(const BaseRequest &); + BaseRequest &operator =(const BaseRequest &); +}; + +class ActivationRequest : public BaseRequest +{ +public: + ActivationRequest(); + int Process(const CryptoContainer &license_data, const char *code, bool offline); + const char *serial() const { return serial_; } +private: + bool VerifyCode(const char *code) const; + bool BuildUrl(const CryptoContainer &license_data, const char *code, bool offline); + + const char *serial_; +}; + +class DeactivationRequest : public BaseRequest +{ +public: + int Process(const CryptoContainer &license_data, const char *serial, bool offline); +private: + bool VerifySerial(const char *serial) const; + bool BuildUrl(const CryptoContainer &license_data, const char *serial, bool offline); +}; +#endif + +#endif
\ No newline at end of file diff --git a/runtime/lin_runtime.mak b/runtime/lin_runtime.mak new file mode 100644 index 0000000..29cda2c --- /dev/null +++ b/runtime/lin_runtime.mak @@ -0,0 +1,32 @@ +SOURCES := core.cc crypto.cc loader.cc licensing_manager.cc string_manager.cc hwid.cc objects.cc utils.cc ../third-party/lzma/LzmaDecode.cc + +PROJECT := lin_runtime +TARGET := $(PROJECT).so +BIN_DIR := ../bin/$(ARCH_DIR)/Release +LIB_TARGET := $(BIN_DIR)/$(PROJECT).a +TMP_DIR := ../tmp/lin/runtime/$(ARCH_DIR)/runtime +PCH_DIR := $(TMP_DIR)/runtime.gch +DEFINES := +LFLAGS := $(LFLAGS) -Wl,--no-undefined -shared -Wl,--wrap=memcpy -Wl,--wrap=__poll_chk -Wl,--wrap=__fdelt_chk +LIBS = ~/curl-7.35.0-$(ARCH_DIR)/lib/libcurl.so -ldl -lrt -L../bin/ -lVMProtectSDK$(ARCH_DIR) +DYLIBS := ../bin/libVMProtectSDK$(ARCH_DIR).so +OBJCOMP := +OBJECTS := $(addprefix $(TMP_DIR)/, $(SOURCES:.cc=.o)) +INCFLAGS := -I ~/curl-7.35.0-$(ARCH_DIR)/include + +include ../lin_common.mak + +clean: + -$(DEL_FILE) $(LIB_TARGET) + -$(DEL_FILE) $(OBJECTS) + -$(DEL_FILE) $(PCH_CPP) + -$(DEL_FILE) $(BIN_TARGET) + +$(LIB_TARGET): $(OBJECTS) $(BIN_DIR)/.sentinel + ar $(SLIBFLAGS) $(LIB_TARGET) $(abspath $(OBJECTS)) $(OBJCOMP) + +$(BIN_TARGET): $(LIB_TARGET) $(OBJCOMP) $(DYLIBS) + $(LINK) $(LFLAGS) -o $(BIN_TARGET) $(OBJECTS) $(LIBS) $(OBJCOMP) + +$(TMP_DIR)/%.o: %.cc $(PCH_CPP) $(TMP_DIR)/%/../.sentinel + $(CXX) -c -include-pch $(PCH_CPP) $(CXXFLAGS) $(INCFLAGS) -o $(abspath $@) $(abspath $<) diff --git a/runtime/lin_runtime32.mak b/runtime/lin_runtime32.mak new file mode 100644 index 0000000..b4ae901 --- /dev/null +++ b/runtime/lin_runtime32.mak @@ -0,0 +1,3 @@ +ARCH := i386-linux-gnu +ARCH_DIR := 32 +include lin_runtime.mak diff --git a/runtime/lin_runtime64.mak b/runtime/lin_runtime64.mak new file mode 100644 index 0000000..fa10b27 --- /dev/null +++ b/runtime/lin_runtime64.mak @@ -0,0 +1,4 @@ +ARCH := x86_64-linux-gnu +ARCH_DIR := 64 +LFLAGS := $(LFLAGS) -Wl,-z,max-page-size=4096 +include lin_runtime.mak diff --git a/runtime/loader.cc b/runtime/loader.cc new file mode 100644 index 0000000..7b70fc9 --- /dev/null +++ b/runtime/loader.cc @@ -0,0 +1,2946 @@ +#include "common.h" +#include "loader.h" +#include "crypto.h" +#include "../third-party/lzma/LzmaDecode.h" + +#define VIRTUAL_PROTECT_ERROR reinterpret_cast<const void *>(1) +#define UNPACKER_ERROR reinterpret_cast<const void *>(2) +#define INTERNAL_GPA_ERROR reinterpret_cast<const void *>(3) +#define CPU_HASH_ERROR reinterpret_cast<const void *>(5) + +#define DECRYPT(str, pos) (str[pos] ^ (_rotl32(FACE_STRING_DECRYPT_KEY, static_cast<int>(pos)) + pos)) + +static void *LoaderAlloc(size_t size) +{ +#ifdef VMP_GNU + return malloc(size); +#elif defined(WIN_DRIVER) + return ExAllocatePool((POOL_TYPE)FACE_NON_PAGED_POOL_NX, size); +#else + return LocalAlloc(0, size); +#endif +} + +static void LoaderFree(void *address) +{ +#ifdef VMP_GNU + free(address); +#elif defined(WIN_DRIVER) + if (address) + ExFreePool(address); +#else + LocalFree(address); +#endif +} + +NOINLINE bool LoaderFindFirmwareVendor(const uint8_t *data, size_t data_size) +{ + for (size_t i = 0; i < data_size; i++) { +#ifdef __unix__ + if (i + 3 < data_size && data[i + 0] == 'Q' && data[i + 1] == 'E' && data[i + 2] == 'M' && data[i + 3] == 'U') + return true; + if (i + 8 < data_size && 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_size && 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; +#else + if (i + 9 < data_size && 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; +#endif + if (i + 5 < data_size && 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_size && 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; +} + +#ifndef VMP_GNU + +#define TOLOWER(c) ((c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c) + +int Loader_stricmp(const char *str1, const char *str2, bool is_enc) +{ + unsigned char c1; + unsigned char c2; + size_t pos = 0; + do { + c1 = *(str1++); + c2 = *(str2++); + if (is_enc) { + c1 ^= static_cast<unsigned char>(_rotl32(FACE_STRING_DECRYPT_KEY, static_cast<int>(pos)) + pos); + pos++; + } + c1 = TOLOWER(c1); + c2 = TOLOWER(c2); + if (!c1) + break; + } while (c1 == c2); + + if (c1 < c2) + return -1; + else if (c1 > c2) + return 1; + return 0; +} + +int Loader_strcmp(const char *str1, const char *str2, bool is_enc) +{ + unsigned char c1; + unsigned char c2; + size_t pos = 0; + do { + c1 = *(str1++); + c2 = *(str2++); + if (is_enc) { + c1 ^= (_rotl32(FACE_STRING_DECRYPT_KEY, static_cast<int>(pos)) + pos); + pos++; + } + if (!c1) + break; + } while (c1 == c2); + + if (c1 < c2) + return -1; + else if (c1 > c2) + return 1; + return 0; +} + +#ifdef WIN_DRIVER + +int Loader_cmp_module(const char *str1, const char *str2, bool is_enc) +{ + unsigned char c1; + unsigned char c2; + size_t pos = 0; + do { + c1 = *(str1++); + c2 = *(str2++); + if (is_enc) { + c1 ^= static_cast<unsigned char>(_rotl32(FACE_STRING_DECRYPT_KEY, static_cast<int>(pos)) + pos); + pos++; + } + c1 = TOLOWER(c1); + c2 = TOLOWER(c2); + if (!c1) + break; + } while (c1 == c2); + + if (c1 == '.' && c2 == 0) + return 0; + if (c1 < c2) + return -1; + else if (c1 > c2) + return 1; + return 0; +} + +HMODULE WINAPI LoaderGetModuleHandle(const char *name) +{ + HMODULE module = NULL; + SYSTEM_MODULE_INFORMATION *buffer = NULL; + ULONG buffer_size = 0; + + NTSTATUS status = NtQuerySystemInformation(SystemModuleInformation, &buffer, 0, &buffer_size); + if (buffer_size) { + buffer = static_cast<SYSTEM_MODULE_INFORMATION *>(LoaderAlloc(buffer_size * 2)); + if (buffer) { + status = NtQuerySystemInformation(SystemModuleInformation, buffer, buffer_size * 2, &buffer_size); + if (NT_SUCCESS(status)) { + PVOID known_api; + if (Loader_cmp_module(reinterpret_cast<const char *>(FACE_NTOSKRNL_NAME), name, true) == 0) + known_api = &IoAllocateMdl; + else if (Loader_cmp_module(reinterpret_cast<const char *>(FACE_HAL_NAME), name, true) == 0) + known_api = &KeQueryPerformanceCounter; + else + known_api = NULL; + + if (known_api) { + // search module by address + for (size_t i = 0; i < buffer->Count; i++) { + SYSTEM_MODULE_ENTRY *module_entry = &buffer->Module[i]; + if (module_entry->BaseAddress < known_api && static_cast<uint8_t *>(module_entry->BaseAddress) + module_entry->Size > known_api) { + module = reinterpret_cast<HMODULE>(module_entry->BaseAddress); + break; + } + } + } else { + // search module by name + for (size_t i = 0; i < buffer->Count; i++) { + SYSTEM_MODULE_ENTRY *module_entry = &buffer->Module[i]; + if (Loader_cmp_module(module_entry->Name + module_entry->PathLength, name, false) == 0) { + module = reinterpret_cast<HMODULE>(module_entry->BaseAddress); + break; + } + } + } + } + LoaderFree(buffer); + } + } + + return module; +} +#else +HMODULE WINAPI LoaderGetModuleHandle(const char *name) +{ + return GetModuleHandleA(name); +} + +__declspec(noinline) HMODULE LoaderLoadLibraryEnc(const char *name) +{ + // decrypt DLL name + char dll_name[MAX_PATH]; + for (size_t j = 0; j < sizeof(dll_name); j++) { + dll_name[j] = static_cast<char>(DECRYPT(name, j)); + if (!dll_name[j]) + break; + } + return LoadLibraryA(dll_name); +} + +__declspec(noinline) const wchar_t *LoaderFindFileVersion(const uint8_t *ptr, size_t data_size) { + const wchar_t *data = reinterpret_cast<const wchar_t *>(ptr); + data_size /= sizeof(wchar_t); + + for (size_t i = 0; i < data_size; i++) { + if (data_size >= 13) { + if (data[i + 0] == L'F' && data[i + 1] == L'i' && data[i + 2] == L'l' && data[i + 3] == L'e' && data[i + 4] == L'V' && data[i + 5] == L'e' && data[i + 6] == L'r' && + data[i + 7] == L's' && data[i + 8] == L'i' && data[i + 9] == L'o' && data[i + 10] == L'n' && data[i + 11] == 0 && data[i + 12] == 0) + return data + i + 13; + } + if (data_size >= 15) { + if (data[i + 0] == L'P' && data[i + 1] == L'r' && data[i + 2] == L'o' && data[i + 3] == L'd' && data[i + 4] == L'u' && data[i + 5] == L'c' && data[i + 6] == L't' && + data[i + 7] == L'V' && data[i + 8] == L'e' && data[i + 9] == L'r' && data[i + 10] == L's' && data[i + 11] == L'i' && data[i + 12] == L'o' && data[i + 13] == L'n' && data[i + 14] == 0) + return data + i + 15; + } + } + return NULL; +} + +__forceinline uint16_t LoaderParseOSBuildBumber(HMODULE ntdll) +{ + uint16_t os_build_number = 0; + IMAGE_DOS_HEADER *dos_header = reinterpret_cast<IMAGE_DOS_HEADER *>(ntdll); + if (dos_header->e_magic == IMAGE_DOS_SIGNATURE) { + IMAGE_NT_HEADERS *pe_header = reinterpret_cast<IMAGE_NT_HEADERS *>(reinterpret_cast<uint8_t *>(ntdll) + dos_header->e_lfanew); + if (pe_header->Signature == IMAGE_NT_SIGNATURE) { + uint32_t resource_adress = pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; + if (resource_adress) { + const uint8_t *resource_start = reinterpret_cast<const uint8_t *>(ntdll) + resource_adress; + const uint8_t *resource_end = resource_start + pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size; + while (const wchar_t *file_version = LoaderFindFileVersion(resource_start, resource_end - resource_start)) { + os_build_number = 0; + for (size_t i = 0; *file_version; file_version++) { + if (*file_version == L'.') + i++; + else if (i == 2) { + while (wchar_t c = *file_version++) { + if (c >= L'0' && c <= L'9') { + os_build_number *= 10; + os_build_number += c - L'0'; + } + else + break; + } + break; + } + } + + if (IS_KNOWN_WINDOWS_BUILD(os_build_number)) + break; + + resource_start = reinterpret_cast<const uint8_t *>(file_version); + } + } + } + } + return os_build_number; +} + +__forceinline uint32_t LoaderParseSyscall(const void *p) +{ + if (const uint8_t *ptr = reinterpret_cast<const uint8_t *>(p)) { +#ifdef _WIN64 + if (ptr[0] == 0x4c && ptr[1] == 0x8b && (ptr[2] & 0xc0) == 0xc0) + ptr += 3; +#endif + if (ptr[0] == 0xb8) + return *reinterpret_cast<const uint32_t *>(ptr + 1); + } + return 0; +} + +#endif + +void *LoaderGetProcAddress(HMODULE module, const char *proc_name, bool is_enc) +{ + // check input + if (!module || !proc_name) + return NULL; + + // check module's header + IMAGE_DOS_HEADER *dos_header = reinterpret_cast<IMAGE_DOS_HEADER *>(module); + if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) + return NULL; + + // check NT header + IMAGE_NT_HEADERS *pe_header = reinterpret_cast<IMAGE_NT_HEADERS *>(reinterpret_cast<uint8_t *>(module) + dos_header->e_lfanew); + if (pe_header->Signature != IMAGE_NT_SIGNATURE) + return NULL; + + // get the export directory + uint32_t export_adress = pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + if (!export_adress) + return NULL; + + uint32_t export_size = pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; + uint32_t address; + uint32_t ordinal_index = -1; + IMAGE_EXPORT_DIRECTORY *export_directory = reinterpret_cast<IMAGE_EXPORT_DIRECTORY *>(reinterpret_cast<uint8_t *>(module) + export_adress); + + if (proc_name <= reinterpret_cast<const char *>(0xFFFF)) { + // ordinal + ordinal_index = static_cast<uint32_t>(INT_PTR(proc_name)) - export_directory->Base; + // index is either less than base or bigger than number of functions + if (ordinal_index >= export_directory->NumberOfFunctions) + return NULL; + // get the function offset by the ordinal + address = (reinterpret_cast<uint32_t *>(reinterpret_cast<uint8_t *>(module) + export_directory->AddressOfFunctions))[ordinal_index]; + // check for empty offset + if (!address) + return NULL; + } else { + // name of function + if (export_directory->NumberOfNames) { + // start binary search + int left_index = 0; + int right_index = export_directory->NumberOfNames - 1; + uint32_t *names = reinterpret_cast<uint32_t *>(reinterpret_cast<uint8_t *>(module) + export_directory->AddressOfNames); + while (left_index <= right_index) { + uint32_t cur_index = (left_index + right_index) >> 1; + switch (Loader_strcmp(proc_name, (const char *)(reinterpret_cast<uint8_t *>(module) + names[cur_index]), is_enc)) { + case 0: + ordinal_index = (reinterpret_cast<WORD *>(reinterpret_cast<uint8_t *>(module) + export_directory->AddressOfNameOrdinals))[cur_index]; + left_index = right_index + 1; + break; + case -1: + right_index = cur_index - 1; + break; + case 1: + left_index = cur_index + 1; + break; + } + } + } + // if nothing has been found + if (ordinal_index >= export_directory->NumberOfFunctions) + return NULL; + // get the function offset by the ordinal + address = (reinterpret_cast<uint32_t *>(reinterpret_cast<uint8_t *>(module) + export_directory->AddressOfFunctions))[ordinal_index]; + if (!address) + return NULL; + } + + // if it is just a pointer - return it + if (address < export_adress || address >= export_adress + export_size) + return reinterpret_cast<FARPROC>(reinterpret_cast<uint8_t *>(module) + address); + + // it is a forward + const char *name = reinterpret_cast<const char *>(reinterpret_cast<uint8_t *>(module) + address); // get a pointer to the module's name + const char *tmp = name; + const char *name_dot = NULL; + // get a pointer to the function's name + while (*tmp) { + if (*tmp == '.') { + name_dot = tmp; + break; + } + tmp++; + } + if (!name_dot) + return NULL; + + size_t name_len = name_dot - name; + if (name_len >= MAX_PATH) + return NULL; + + // copy module name + char file_name[MAX_PATH]; + size_t i; + for (i = 0; i < name_len && name[i] != 0; i++) { + file_name[i] = name[i]; + } + file_name[i] = 0; + + HMODULE tmp_module = LoaderGetModuleHandle(file_name); +#ifndef WIN_DRIVER + if (!tmp_module) + tmp_module = LoadLibraryA(file_name); +#endif + if (!tmp_module) + return NULL; + + if (tmp_module == module) { + // forwarded to itself +#ifdef WIN_DRIVER + return NULL; +#else + if (is_enc) { + for (i = 0; i < sizeof(file_name); i++) { + char c = proc_name[i]; + c ^= (_rotl32(FACE_STRING_DECRYPT_KEY, static_cast<int>(i)) + i); + file_name[i] = c; + if (!c) + break; + } + proc_name = file_name; + } + return GetProcAddress(module, proc_name); +#endif + } + + // now the function's name + // if it is not an ordinal, just forward it + if (name_dot[1] != '#') + return LoaderGetProcAddress(tmp_module, name_dot + 1, false); + + // it is an ordinal + tmp = name_dot + 2; + int ordinal = 0; + while (*tmp) { + char c = *(tmp++); + if (c >= '0' && c <= '9') { + ordinal = ordinal * 10 + c - '0'; + } else { + break; + } + } + return LoaderGetProcAddress(tmp_module, reinterpret_cast<const char *>(INT_PTR(ordinal)), false); +} + +__declspec(noinline) HMODULE LoaderGetModuleHandleEnc(const char *name) +{ + // decrypt DLL name + char dll_name[MAX_PATH]; + for (size_t j = 0; j < sizeof(dll_name); j++) { + dll_name[j] = static_cast<char>(DECRYPT(name, j)); + if (!dll_name[j]) + break; + } + return LoaderGetModuleHandle(dll_name); +} + +__forceinline void InitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString) +{ + if (SourceString) + DestinationString->MaximumLength = (DestinationString->Length = (USHORT)(wcslen(SourceString) * sizeof(WCHAR))) + sizeof(UNICODE_NULL); + else + DestinationString->MaximumLength = DestinationString->Length = 0; + + DestinationString->Buffer = (PWCH)SourceString; +} + +#endif // VMP_GNU + +#if defined(__unix__) +struct LoaderString { +public: + LoaderString() + { + capacity_ = 2; + buffer_ = reinterpret_cast<char *>(LoaderAlloc(capacity_)); + buffer_[0] = 0; + size_ = 0; + } + ~LoaderString() + { + LoaderFree(buffer_); + } + const char *c_str() const { return buffer_; } + size_t size() const { return size_; } + LoaderString &operator +=(char c) + { + add_size(1); + + buffer_[size_++] = c; + buffer_[size_] = 0; + return *this; + } + LoaderString &operator +=(const char *str) + { + size_t str_len = strlen(str); + + add_size(str_len); + + __movsb(buffer_ + size_, str, str_len); + size_ += str_len; + buffer_[size_] = 0; + return *this; + } +private: + void add_size(size_t size) + { + size_t new_size = size_ + size + 1; + if (new_size <= capacity_) + return; + + while (capacity_ < new_size) { + capacity_ <<= 1; + } + char *new_buffer = reinterpret_cast<char *>(LoaderAlloc(capacity_)); + __movsb(new_buffer, buffer_, size_ + 1); + LoaderFree(buffer_); + buffer_ = new_buffer; + } + + char *buffer_; + size_t size_; + size_t capacity_; +}; +#endif + +enum MessageType { + mtInitializationError, + mtProcNotFound, + mtOrdinalNotFound, + mtFileCorrupted, + mtDebuggerFound, + mtUnregisteredVersion, + mtVirtualMachineFound +}; + +void LoaderMessage(MessageType type, const void *param1 = NULL, const void *param2 = NULL) +{ + const VMP_CHAR *message; + bool need_format = false; + switch (type) { + case mtDebuggerFound: + message = reinterpret_cast<const VMP_CHAR *>(FACE_DEBUGGER_FOUND); + break; + case mtVirtualMachineFound: + message = reinterpret_cast<const VMP_CHAR *>(FACE_VIRTUAL_MACHINE_FOUND); + break; + case mtFileCorrupted: + message = reinterpret_cast<const VMP_CHAR *>(FACE_FILE_CORRUPTED); + break; + case mtUnregisteredVersion: + message = reinterpret_cast<const VMP_CHAR *>(FACE_UNREGISTERED_VERSION); + break; + case mtInitializationError: + message = reinterpret_cast<const VMP_CHAR *>(FACE_INITIALIZATION_ERROR); + need_format = true; + break; + case mtProcNotFound: + message = reinterpret_cast<const VMP_CHAR *>(FACE_PROC_NOT_FOUND); + need_format = true; + break; + case mtOrdinalNotFound: + message = reinterpret_cast<const VMP_CHAR *>(FACE_ORDINAL_NOT_FOUND); + need_format = true; + break; + default: + return; + } + + VMP_CHAR message_buffer[1024]; + VMP_CHAR *dst = message_buffer; + VMP_CHAR *end = dst + _countof(message_buffer) - 1; + size_t param_index = 0; + + for (size_t j = 0; dst < end; j++) { + VMP_CHAR c = static_cast<VMP_CHAR>(DECRYPT(message, j)); + if (!c) + break; + + if (need_format && c == '%') { + j++; + const void *param = (param_index == 0) ? param1 : param2; + param_index++; + c = static_cast<VMP_CHAR>(DECRYPT(message, j)); + if (c == 's') { + const char *src = reinterpret_cast<const char *>(param); + + while (*src && dst < end) { + *(dst++) = *(src++); + } + } else if (c == 'c') { + const char *src = reinterpret_cast<const char *>(param); + + for (size_t k = 0; dst < end; k++) { + char b = static_cast<char>(DECRYPT(src, k)); + if (!b) + break; + *(dst++) = b; + } + } else if (c == 'd') { + size_t value = reinterpret_cast<size_t>(param); + char buff[20]; + char *src = buff + _countof(buff) - 1; + + *src = 0; + do { + *(--src) = '0' + value % 10; + value /= 10; + } while (value); + + while (*src && dst < end) { + *(dst++) = *(src++); + } + } + } else { + *(dst++) = c; + } + } + *dst = 0; + message = message_buffer; + + if (!message[0]) + return; + +#ifdef __APPLE__ + char file_name[PATH_MAX]; + uint32_t name_size = sizeof(file_name); + const char *title = file_name; + if (_NSGetExecutablePath(file_name, &name_size) == 0) { + for (size_t i = 0; i < sizeof(file_name); i++) { + if (!file_name[i]) + break; + if (file_name[i] == '/') + title = file_name + i + 1; + } + } else { + file_name[0] = 'F'; + file_name[1] = 'a'; + file_name[2] = 't'; + file_name[3] = 'a'; + file_name[4] = 'l'; + file_name[5] = ' '; + file_name[6] = 'E'; + file_name[7] = 'r'; + file_name[8] = 'r'; + file_name[9] = 'o'; + file_name[10] = 'r'; + file_name[11] = 0; + } + + CFStringRef title_ref = CFStringCreateWithCString(NULL, title, kCFStringEncodingMacRoman); + CFStringRef message_ref = CFStringCreateWithCString(NULL, message, kCFStringEncodingUTF8); + CFOptionFlags result; + + CFUserNotificationDisplayAlert( + 0, // no timeout + (type == mtUnregisteredVersion) ? kCFUserNotificationCautionAlertLevel : kCFUserNotificationStopAlertLevel, //change it depending message_type flags ( MB_ICONASTERISK.... etc.) + NULL, //icon url, use default, you can change it depending message_type flags + NULL, //not used + NULL, //localization of strings + title_ref, //title text + message_ref, //message text + NULL, //default "ok" text in button + NULL, //alternate button title + NULL, //other button title, null--> no other button + &result //response flags + ); + + CFRelease(title_ref); + CFRelease(message_ref); +#elif defined(__unix__) + char file_name[PATH_MAX]; + char self_exe[] = {'/', 'p', 'r', 'o', 'c', '/', 's', 'e', 'l', 'f', '/', 'e', 'x', 'e', 0}; + const char *title = file_name; + ssize_t len = ::readlink(self_exe, file_name, sizeof(file_name) - 1); + if (len != -1) { + for (ssize_t i = 0; i < len; i++) { + if (file_name[i] == '/') + title = file_name + i + 1; + if (file_name[i] == '\'' || file_name[i] == '\\') + file_name[i] = '"'; + } + file_name[len] = '\0'; + } else { + file_name[0] = 'F'; + file_name[1] = 'a'; + file_name[2] = 't'; + file_name[3] = 'a'; + file_name[4] = 'l'; + file_name[5] = ' '; + file_name[6] = 'E'; + file_name[7] = 'r'; + file_name[8] = 'r'; + file_name[9] = 'o'; + file_name[10] = 'r'; + file_name[11] = 0; + } + LoaderString cmd_line; + { + char str[] = {'z', 'e', 'n', 'i', 't', 'y', 0}; + cmd_line += str; + } + if (type == mtUnregisteredVersion) + { + char str[] = {' ', '-', '-', 'w', 'a', 'r', 'n', 'i', 'n', 'g', 0}; + cmd_line += str; + } + else + { + char str[] = {' ', '-', '-', 'e', 'r', 'r', 'o', 'r', 0}; + cmd_line += str; + } + { + char str[] = {' ', '-', '-', 'n', 'o', '-', 'm', 'a', 'r', 'k', 'u', 'p', 0}; + cmd_line += str; + } + { + char str[] = {' ', '-', '-', 't', 'i', 't', 'l', 'e', '=', '\'', 0}; + cmd_line += str; + cmd_line += title; + cmd_line += '\''; + } + { + char str[] = {' ', '-', '-', 't', 'e', 'x', 't', '=', '\'', 0}; + cmd_line += str; + char *msg_ptr = message_buffer; + while (*msg_ptr) + { + if (*msg_ptr == '\'' || *msg_ptr == '\\') + *msg_ptr = '"'; + msg_ptr++; + } + cmd_line += message; + cmd_line += '\''; + } + int status = system(cmd_line.c_str()); + if (status == -1 || WEXITSTATUS(status) == 127) + puts(message); +#elif defined(WIN_DRIVER) + DbgPrint(reinterpret_cast<const char *>(FACE_DRIVER_FORMAT_VALUE), message); +#else + wchar_t file_name[MAX_PATH]; + const wchar_t *title = file_name; + if (GetModuleFileNameW(reinterpret_cast<HMODULE>(FACE_IMAGE_BASE), file_name, _countof(file_name))) { + for (size_t i = 0; i < _countof(file_name); i++) { + if (!file_name[i]) + break; + if (file_name[i] == '\\') + title = file_name + i + 1; + } + } else { + file_name[0] = 'F'; + file_name[1] = 'a'; + file_name[2] = 't'; + file_name[3] = 'a'; + file_name[4] = 'l'; + file_name[5] = ' '; + file_name[6] = 'E'; + file_name[7] = 'r'; + file_name[8] = 'r'; + file_name[9] = 'o'; + file_name[10] = 'r'; + file_name[11] = 0; + } + + HMODULE ntdll = LoaderGetModuleHandleEnc(reinterpret_cast<const char *>(FACE_NTDLL_NAME)); + + typedef NTSTATUS(NTAPI tNtRaiseHardError)(NTSTATUS ErrorStatus, ULONG NumberOfParameters, + ULONG UnicodeStringParameterMask, PULONG_PTR Parameters, + ULONG ValidResponseOptions, + HardErrorResponse *Response); + + if (tNtRaiseHardError *raise_hard_error = reinterpret_cast<tNtRaiseHardError *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_RAISE_HARD_ERROR_NAME), true))) { + UNICODE_STRING message_str; + UNICODE_STRING title_str; + + InitUnicodeString(&message_str, (PWSTR)message); + InitUnicodeString(&title_str, (PWSTR)title); + + ULONG_PTR params[4] = { + (ULONG_PTR)&message_str, + (ULONG_PTR)&title_str, + ( + (ULONG)ResponseButtonOK | + (type == mtUnregisteredVersion ? IconWarning : IconError) + ), + INFINITE + }; + + HardErrorResponse response; + raise_hard_error(STATUS_SERVICE_NOTIFICATION | HARDERROR_OVERRIDE_ERRORMODE, 4, 3, params, 0, &response); + } +#endif +} + +enum { + LOADER_SUCCESS = +#ifdef WIN_DRIVER + STATUS_SUCCESS +#else + TRUE +#endif + , + + LOADER_ERROR = +#ifdef WIN_DRIVER + STATUS_DRIVER_INTERNAL_ERROR +#else + FALSE +#endif +}; + +#ifdef VMP_GNU +EXPORT_API void FreeImage() __asm__ ("FreeImage"); +#endif + +#ifdef WIN_DRIVER +void WINAPI FreeImage(PDRIVER_OBJECT driver_object) +#else +void WINAPI FreeImage() +#endif +{ + SETUP_IMAGE_DATA data; + + uint8_t *image_base = data.image_base(); + uint32_t loader_status = LOADER_ERROR; + GlobalData *loader_data = *(reinterpret_cast<GlobalData**>(image_base + data.storage())); + if (loader_data) { +#ifdef WIN_DRIVER + if (loader_data->driver_unload()) + reinterpret_cast<PDRIVER_UNLOAD>(loader_data->driver_unload())(driver_object); +#endif + + if (uint32_t data_runtime_entry = data.runtime_entry()) { +#ifdef VMP_GNU + typedef void (WINAPI tRuntimeEntry)(HMODULE hModule, bool is_init); + reinterpret_cast<tRuntimeEntry *>(image_base + data_runtime_entry)(reinterpret_cast<HMODULE>(image_base), false); +#elif defined(WIN_DRIVER) + typedef NTSTATUS (tRuntimeEntry)(HMODULE hModule, bool is_init); + reinterpret_cast<tRuntimeEntry *>(image_base + data_runtime_entry)(reinterpret_cast<HMODULE>(image_base), false); +#else + typedef BOOL (WINAPI tRuntimeEntry)(HMODULE hModule, DWORD dwReason, LPVOID lpReserved); + reinterpret_cast<tRuntimeEntry *>(image_base + data_runtime_entry)(reinterpret_cast<HMODULE>(image_base), DLL_PROCESS_DETACH, NULL); +#endif + } + + loader_status = loader_data->loader_status(); + LoaderFree(loader_data); + } + + if (loader_status == LOADER_ERROR) { +#ifdef VMP_GNU + exit(0xDEADC0DE); +#elif defined(WIN_DRIVER) + // do nothing +#else + if (data.options() & LOADER_OPTION_EXIT_PROCESS) + ExitProcess(0xDEADC0DE); +#endif + } +} + +void LoaderProcessFixups(ptrdiff_t delta_base, uint32_t data_fixup_info, uint32_t data_fixup_info_size, uint8_t *image_base, uint8_t *dst_image_base) +{ + size_t i, j, c; + FIXUP_INFO *fixup_info; + for (i = 0; i < data_fixup_info_size; i += fixup_info->BlockSize) { + fixup_info = reinterpret_cast<FIXUP_INFO *>(image_base + data_fixup_info + i); + if (fixup_info->BlockSize < sizeof(FIXUP_INFO)) + break; + + c = (fixup_info->BlockSize - sizeof(FIXUP_INFO)) >> 1; + for (j = 0; j < c; j++) { + uint16_t type_offset = reinterpret_cast<uint16_t *>(fixup_info + 1)[j]; + uint8_t *address = dst_image_base + fixup_info->Address + (type_offset >> 4); + + // need use "if" instead "switch" + uint8_t type = (type_offset & 0x0f); +#ifdef __APPLE__ + if (type == REBASE_TYPE_POINTER) + *(reinterpret_cast<ptrdiff_t *>(address)) += delta_base; + else if (type == REBASE_TYPE_TEXT_ABSOLUTE32) + *(reinterpret_cast<ptrdiff_t *>(address)) += delta_base; +#elif defined(__unix__) + if (type == 8) // R_386_RELATIVE + *(reinterpret_cast<ptrdiff_t *>(address)) += delta_base; +#else + if (type == IMAGE_REL_BASED_HIGHLOW) + *(reinterpret_cast<uint32_t *>(address)) += static_cast<uint32_t>(delta_base); + else if (type == IMAGE_REL_BASED_DIR64) + *(reinterpret_cast<uint64_t *>(address)) += delta_base; + else if (type == IMAGE_REL_BASED_HIGH) + *(reinterpret_cast<uint16_t *>(address)) += static_cast<uint16_t>(delta_base >> 16); + else if (type == IMAGE_REL_BASED_LOW) + *(reinterpret_cast<uint16_t *>(address)) += static_cast<uint16_t>(delta_base); +#endif + } + } +} + +#ifdef VMP_GNU +EXPORT_API uint32_t WINAPI SetupImage() __asm__ ("SetupImage"); +#endif +#ifdef WIN_DRIVER +uint32_t WINAPI SetupImage(bool is_init, PDRIVER_OBJECT driver_object) +#else +uint32_t WINAPI SetupImage() +#endif +{ + size_t i, j; + uint64_t session_key; + SETUP_IMAGE_DATA data; + + uint8_t *image_base = data.image_base(); + uint8_t *file_base = data.file_base(); + uint8_t *dst_image_base = image_base; + ptrdiff_t delta_base = image_base - file_base; + + GlobalData *tmp_loader_data = *(reinterpret_cast<GlobalData**>(image_base + data.storage())); + if (tmp_loader_data) { +#ifdef WIN_DRIVER + if (!is_init && tmp_loader_data->loader_status() == LOADER_SUCCESS && driver_object->DriverUnload) { + tmp_loader_data->set_driver_unload(reinterpret_cast<size_t>(driver_object->DriverUnload)); + driver_object->DriverUnload = FreeImage; + } +#endif + return tmp_loader_data->loader_status(); + } + + tmp_loader_data = reinterpret_cast<GlobalData *>(LoaderAlloc(sizeof(GlobalData))); + tmp_loader_data->set_loader_status(LOADER_ERROR); + tmp_loader_data->set_is_patch_detected(false); + tmp_loader_data->set_is_debugger_detected(false); + tmp_loader_data->set_server_date(0); + tmp_loader_data->set_loader_crc_info(data.loader_crc_info()); + tmp_loader_data->set_loader_crc_size(0); + size_t crc_image_size = 0; + tmp_loader_data->set_crc_image_size(crc_image_size); +#ifdef VMP_GNU +#elif defined(WIN_DRIVER) + tmp_loader_data->set_driver_unload(0); +#else + tmp_loader_data->set_os_build_number(0); +#endif + + size_t cpu_salt = 0; +#ifdef VMP_GNU +#elif defined(WIN_DRIVER) + HMODULE ntoskrnl = LoaderGetModuleHandleEnc(reinterpret_cast<const char *>(FACE_NTOSKRNL_NAME)); +#else + typedef NTSTATUS(NTAPI tNtClose)(HANDLE Handle); + typedef NTSTATUS(NTAPI tNtOpenFile)(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess, ULONG OpenOptions); + typedef NTSTATUS(NTAPI tNtCreateSection)(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PLARGE_INTEGER MaximumSize, ULONG SectionPageProtection, ULONG AllocationAttributes, HANDLE FileHandle); + typedef NTSTATUS(NTAPI tNtMapViewOfSection)(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, SECTION_INHERIT InheritDisposition, ULONG AllocationType, ULONG Win32Protect); + typedef NTSTATUS(NTAPI tNtUnmapViewOfSection)(HANDLE ProcessHandle, PVOID BaseAddress); + typedef NTSTATUS(NTAPI tNtQueryInformationProcess)(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength); + typedef NTSTATUS(NTAPI tNtSetInformationThread)(HANDLE ThreadHandle, THREADINFOCLASS ThreadInformationClass, PVOID ThreadInformation, ULONG ThreadInformationLength); + typedef NTSTATUS(NTAPI tNtProtectVirtualMemory)(HANDLE ProcesssHandle, LPVOID *BaseAddress, SIZE_T *Size, DWORD NewProtect, PDWORD OldProtect); + typedef NTSTATUS(NTAPI tNtOpenSection)(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes); + typedef NTSTATUS(NTAPI tNtQueryVirtualMemory)(HANDLE ProcessHandle, PVOID BaseAddress, MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID MemoryInformation, SIZE_T MemoryInformationLength, PSIZE_T ReturnLength); + typedef NTSTATUS(NTAPI tNtSetInformationProcess)(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength); + + HMODULE kernel32 = LoaderGetModuleHandleEnc(reinterpret_cast<const char *>(FACE_KERNEL32_NAME)); + HMODULE ntdll = LoaderGetModuleHandleEnc(reinterpret_cast<const char *>(FACE_NTDLL_NAME)); + HANDLE process = NtCurrentProcess(); + HANDLE thread = NtCurrentThread(); + size_t syscall = FACE_SYSCALL; + uint32_t sc_close = 0; + uint32_t sc_virtual_protect = 0; + uint32_t sc_open_file = 0; + uint32_t sc_create_section = 0; + uint32_t sc_map_view_of_section = 0; + uint32_t sc_unmap_view_of_section = 0; + uint32_t sc_query_information_process = 0; + uint32_t sc_set_information_thread = 0; + uint32_t sc_query_virtual_memory = 0; +#ifdef _WIN64 + PEB64 *peb = reinterpret_cast<PEB64 *>(__readgsqword(0x60)); +#else + PEB32 *peb = reinterpret_cast<PEB32 *>(__readfsdword(0x30)); +#endif + cpu_salt = peb->OSBuildNumber << 7; + +#ifndef DEMO + if (LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_WINE_GET_VERSION_NAME), true) == NULL) { +#ifndef _WIN64 + BOOL is_wow64 = FALSE; + typedef BOOL(WINAPI tIsWow64Process)(HANDLE Process, PBOOL Wow64Process); + tIsWow64Process *is_wow64_process = reinterpret_cast<tIsWow64Process *>(LoaderGetProcAddress(kernel32, reinterpret_cast<const char *>(FACE_IS_WOW64_PROCESS_NAME), true)); + if (is_wow64_process) + is_wow64_process(process, &is_wow64); +#endif + + uint16_t os_build_number = peb->OSBuildNumber; + if (!IS_KNOWN_WINDOWS_BUILD(os_build_number)) { + // parse FileVersion/ProductVersion from NTDLL resources + os_build_number = LoaderParseOSBuildBumber(ntdll); + if (!IS_KNOWN_WINDOWS_BUILD(os_build_number)) { + // load copy of NTDLL + tNtQueryVirtualMemory *query_virtual_memory = reinterpret_cast<tNtQueryVirtualMemory *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_QUERY_VIRTUAL_MEMORY_NAME), true)); + tNtOpenFile *open_file = reinterpret_cast<tNtOpenFile *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_OPEN_FILE_NAME), true)); + tNtCreateSection *create_section = reinterpret_cast<tNtCreateSection *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_CREATE_SECTION_NAME), true)); + tNtMapViewOfSection *map_view_of_section = reinterpret_cast<tNtMapViewOfSection *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_MAP_VIEW_OF_SECTION), true)); + tNtUnmapViewOfSection *unmap_view_of_section = reinterpret_cast<tNtUnmapViewOfSection *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_UNMAP_VIEW_OF_SECTION), true)); + tNtClose *close = reinterpret_cast<tNtClose *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_CLOSE), true)); + + if (!query_virtual_memory + || !create_section + || !open_file + || !map_view_of_section + || !unmap_view_of_section + || !close) { + LoaderMessage(mtInitializationError, INTERNAL_GPA_ERROR); + return LOADER_ERROR; + } + + os_build_number = 0; + uint8_t buffer[MAX_PATH * sizeof(wchar_t)]; + if (NT_SUCCESS(query_virtual_memory(process, ntdll, MemoryMappedFilenameInformation, buffer, sizeof(buffer), NULL))) { + HANDLE file_handle; + OBJECT_ATTRIBUTES object_attributes; + IO_STATUS_BLOCK io_status_block; + + InitializeObjectAttributes(&object_attributes, reinterpret_cast<UNICODE_STRING *>(buffer), 0, NULL, NULL); + if (NT_SUCCESS(open_file(&file_handle, GENERIC_READ | SYNCHRONIZE | FILE_READ_ATTRIBUTES, &object_attributes, &io_status_block, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT))) { + HANDLE file_map; + InitializeObjectAttributes(&object_attributes, NULL, 0, NULL, NULL); + if (NT_SUCCESS(create_section(&file_map, SECTION_MAP_READ, &object_attributes, NULL, PAGE_READONLY, SEC_IMAGE_NO_EXECUTE, file_handle))) { + void *copy_ntdll = NULL; + SIZE_T file_size = 0; + LARGE_INTEGER offset; + offset.LowPart = 0; + offset.HighPart = 0; + if (NT_SUCCESS(map_view_of_section(file_map, process, ©_ntdll, NULL, 0, &offset, &file_size, ViewShare, 0, PAGE_READONLY))) { + os_build_number = LoaderParseOSBuildBumber((HMODULE)copy_ntdll); + + if (!IS_KNOWN_WINDOWS_BUILD(os_build_number)) { + sc_close = LoaderParseSyscall(LoaderGetProcAddress((HMODULE)copy_ntdll, reinterpret_cast<const char *>(FACE_NT_CLOSE), true)); + sc_virtual_protect = LoaderParseSyscall(LoaderGetProcAddress((HMODULE)copy_ntdll, reinterpret_cast<const char *>(FACE_NT_VIRTUAL_PROTECT_NAME), true)); + sc_open_file = LoaderParseSyscall(LoaderGetProcAddress((HMODULE)copy_ntdll, reinterpret_cast<const char *>(FACE_NT_OPEN_FILE_NAME), true)); + sc_create_section = LoaderParseSyscall(LoaderGetProcAddress((HMODULE)copy_ntdll, reinterpret_cast<const char *>(FACE_NT_CREATE_SECTION_NAME), true)); + sc_map_view_of_section = LoaderParseSyscall(LoaderGetProcAddress((HMODULE)copy_ntdll, reinterpret_cast<const char *>(FACE_NT_MAP_VIEW_OF_SECTION), true)); + sc_unmap_view_of_section = LoaderParseSyscall(LoaderGetProcAddress((HMODULE)copy_ntdll, reinterpret_cast<const char *>(FACE_NT_UNMAP_VIEW_OF_SECTION), true)); + sc_query_information_process = LoaderParseSyscall(LoaderGetProcAddress((HMODULE)copy_ntdll, reinterpret_cast<const char *>(FACE_NT_QUERY_INFORMATION_PROCESS_NAME), true)); + sc_set_information_thread = LoaderParseSyscall(LoaderGetProcAddress((HMODULE)copy_ntdll, reinterpret_cast<const char *>(FACE_NT_SET_INFORMATION_THREAD_NAME), true)); + sc_query_virtual_memory = LoaderParseSyscall(LoaderGetProcAddress((HMODULE)copy_ntdll, reinterpret_cast<const char *>(FACE_QUERY_VIRTUAL_MEMORY_NAME), true)); + +#ifndef _WIN64 + if (is_wow64) { + // wow64 version of ntdll uses upper 16 bits for encoding information about arguments + sc_close = static_cast<uint16_t>(sc_close); + sc_virtual_protect = static_cast<uint16_t>(sc_virtual_protect); + sc_open_file = static_cast<uint16_t>(sc_open_file); + sc_create_section = static_cast<uint16_t>(sc_create_section); + sc_map_view_of_section = static_cast<uint16_t>(sc_map_view_of_section); + sc_unmap_view_of_section = static_cast<uint16_t>(sc_unmap_view_of_section); + sc_query_information_process = static_cast<uint16_t>(sc_query_information_process); + sc_set_information_thread = static_cast<uint16_t>(sc_set_information_thread); + sc_query_virtual_memory = static_cast<uint16_t>(sc_query_virtual_memory); + } +#endif + } + + unmap_view_of_section(process, copy_ntdll); + } + close(file_map); + } + close(file_handle); + } + } + } + + if (!os_build_number) { + if (data.options() & LOADER_OPTION_CHECK_DEBUGGER) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + tmp_loader_data->set_is_debugger_detected(true); + } + } + + tmp_loader_data->set_os_build_number(os_build_number); + + if (os_build_number == WINDOWS_XP) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x0019; + sc_virtual_protect = 0x0089; + sc_open_file = 0x0074; + sc_create_section = 0x0032; + sc_map_view_of_section = 0x006c; + sc_unmap_view_of_section = 0x010b; + sc_query_information_process = 0x009a; + sc_set_information_thread = 0x00e5; + sc_query_virtual_memory = 0x00b2; + } + else +#endif + { + sc_close = 0x000c; + sc_virtual_protect = 0x004d; + sc_open_file = 0x0030; + sc_create_section = 0x0047; + sc_map_view_of_section = 0x0025; + sc_unmap_view_of_section = 0x0027; + sc_query_information_process = 0x0016; + sc_set_information_thread = 0x000a; + sc_query_virtual_memory = 0x0020; + } + } + else if (os_build_number == WINDOWS_2003) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x001b; + sc_virtual_protect = 0x008f; + sc_open_file = 0x007a; + sc_create_section = 0x0034; + sc_map_view_of_section = 0x0071; + sc_unmap_view_of_section = 0x0115; + sc_query_information_process = 0x00a1; + sc_set_information_thread = 0x00ee; + sc_query_virtual_memory = 0x00ba; + } + else +#endif + { + sc_close = 0x000c; + sc_virtual_protect = 0x004d; + sc_open_file = 0x0030; + sc_create_section = 0x0047; + sc_map_view_of_section = 0x0025; + sc_unmap_view_of_section = 0x0027; + sc_query_information_process = 0x0016; + sc_set_information_thread = 0x000a; + sc_query_virtual_memory = 0x0020; + } + } + else if (os_build_number == WINDOWS_VISTA) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x0030; + sc_virtual_protect = 0x00d2; + sc_open_file = 0x00ba; + sc_create_section = 0x004b; + sc_map_view_of_section = 0x00b1; + sc_unmap_view_of_section = 0x0160; + sc_query_information_process = 0x00e4; + sc_set_information_thread = 0x0136; + sc_query_virtual_memory = 0x00fd; + } + else +#endif + { + sc_close = 0x000c; + sc_virtual_protect = 0x004d; + sc_open_file = 0x0030; + sc_create_section = 0x0047; + sc_map_view_of_section = 0x0025; + sc_unmap_view_of_section = 0x0027; + sc_query_information_process = 0x0016; + sc_set_information_thread = 0x000a; + sc_query_virtual_memory = 0x0020; + } + } + else if (os_build_number == WINDOWS_VISTA_SP1) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x0030; + sc_virtual_protect = 0x00d2; + sc_open_file = 0x00ba; + sc_create_section = 0x004b; + sc_map_view_of_section = 0x00b1; + sc_unmap_view_of_section = 0x015c; + sc_query_information_process = 0x00e4; + sc_set_information_thread = 0x0132; + sc_query_virtual_memory = 0x00fd; + } + else +#endif + { + sc_close = 0x000c; + sc_virtual_protect = 0x004d; + sc_open_file = 0x0030; + sc_create_section = 0x0047; + sc_map_view_of_section = 0x0025; + sc_unmap_view_of_section = 0x0027; + sc_query_information_process = 0x0016; + sc_set_information_thread = 0x000a; + sc_query_virtual_memory = 0x0020; + } + + } + else if (os_build_number == WINDOWS_VISTA_SP2) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x0030; + sc_virtual_protect = 0x00d2; + sc_open_file = 0x00ba; + sc_create_section = 0x004b; + sc_map_view_of_section = 0x00b1; + sc_unmap_view_of_section = 0x015c; + sc_query_information_process = 0x00e4; + sc_set_information_thread = 0x0132; + sc_query_virtual_memory = 0x00fd; + } + else +#endif + { + sc_close = 0x000c; + sc_virtual_protect = 0x004d; + sc_open_file = 0x0030; + sc_create_section = 0x0047; + sc_map_view_of_section = 0x0025; + sc_unmap_view_of_section = 0x0027; + sc_query_information_process = 0x0016; + sc_set_information_thread = 0x000a; + sc_query_virtual_memory = 0x0020; + } + } + else if (os_build_number == WINDOWS_7) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x0032; + sc_virtual_protect = 0x00d7; + sc_open_file = 0x00b3; + sc_create_section = 0x0054; + sc_map_view_of_section = 0x00a8; + sc_unmap_view_of_section = 0x0181; + sc_query_information_process = 0x00ea; + sc_set_information_thread = 0x014f; + sc_query_virtual_memory = 0x010b; + } + else +#endif + { + sc_close = 0x000c; + sc_virtual_protect = 0x004d; + sc_open_file = 0x0030; + sc_create_section = 0x0047; + sc_map_view_of_section = 0x0025; + sc_unmap_view_of_section = 0x0027; + sc_query_information_process = 0x0016; + sc_set_information_thread = 0x000a; + sc_query_virtual_memory = 0x0020; + } + } + else if (os_build_number == WINDOWS_7_SP1) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x0032; + sc_virtual_protect = 0x00d7; + sc_open_file = 0x00b3; + sc_create_section = 0x0054; + sc_map_view_of_section = 0x00a8; + sc_unmap_view_of_section = 0x0181; + sc_query_information_process = 0x00ea; + sc_set_information_thread = 0x014f; + sc_query_virtual_memory = 0x010b; + } + else +#endif + { + sc_close = 0x000c; + sc_virtual_protect = 0x004d; + sc_open_file = 0x0030; + sc_create_section = 0x0047; + sc_map_view_of_section = 0x0025; + sc_unmap_view_of_section = 0x0027; + sc_query_information_process = 0x0016; + sc_set_information_thread = 0x000a; + sc_query_virtual_memory = 0x0020; + } + } + else if (os_build_number == WINDOWS_8) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x0174; + sc_virtual_protect = 0x00c3; + sc_open_file = 0x00e8; + sc_create_section = 0x0150; + sc_map_view_of_section = 0x00f3; + sc_unmap_view_of_section = 0x0013; + sc_query_information_process = 0x00b0; + sc_set_information_thread = 0x0048; + sc_query_virtual_memory = 0x008f; + } + else +#endif + { + sc_close = 0x000d; + sc_virtual_protect = 0x004e; + sc_open_file = 0x0031; + sc_create_section = 0x0048; + sc_map_view_of_section = 0x0026; + sc_unmap_view_of_section = 0x0028; + sc_query_information_process = 0x0017; + sc_set_information_thread = 0x000b; + sc_query_virtual_memory = 0x0021; + } + } + else if (os_build_number == WINDOWS_8_1) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x0179; + sc_virtual_protect = 0x00c6; + sc_open_file = 0x00eb; + sc_create_section = 0x0154; + sc_map_view_of_section = 0x00f6; + sc_unmap_view_of_section = 0x0013; + sc_query_information_process = 0x00b3; + sc_set_information_thread = 0x004b; + sc_query_virtual_memory = 0x0092; + } + else +#endif + { + sc_close = 0x000e; + sc_virtual_protect = 0x004f; + sc_open_file = 0x0032; + sc_create_section = 0x0049; + sc_map_view_of_section = 0x0027; + sc_unmap_view_of_section = 0x0029; + sc_query_information_process = 0x0018; + sc_set_information_thread = 0x000c; + sc_query_virtual_memory = 0x0022; + } + } + else if (os_build_number == WINDOWS_10_TH1) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x0180; + sc_virtual_protect = 0x00c8; + sc_open_file = 0x00ee; + sc_create_section = 0x015a; + sc_map_view_of_section = 0x00fa; + sc_unmap_view_of_section = 0x0014; + sc_query_information_process = 0x00b5; + sc_set_information_thread = 0x004c; + sc_query_virtual_memory = 0x0094; + } + else +#endif + { + sc_close = 0x000f; + sc_virtual_protect = 0x0050; + sc_open_file = 0x0033; + sc_create_section = 0x004a; + sc_map_view_of_section = 0x0028; + sc_unmap_view_of_section = 0x002a; + sc_query_information_process = 0x0019; + sc_set_information_thread = 0x000d; + sc_query_virtual_memory = 0x0023; + } + } + else if (os_build_number == WINDOWS_10_TH2) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x0183; + sc_virtual_protect = 0x00c8; + sc_open_file = 0x00ee; + sc_create_section = 0x015c; + sc_map_view_of_section = 0x00fa; + sc_unmap_view_of_section = 0x0014; + sc_query_information_process = 0x00b5; + sc_set_information_thread = 0x004c; + sc_query_virtual_memory = 0x0094; + } + else +#endif + { + sc_close = 0x000f; + sc_virtual_protect = 0x0050; + sc_open_file = 0x0033; + sc_create_section = 0x004a; + sc_map_view_of_section = 0x0028; + sc_unmap_view_of_section = 0x002a; + sc_query_information_process = 0x0019; + sc_set_information_thread = 0x000d; + sc_query_virtual_memory = 0x0023; + } + } + else if (os_build_number == WINDOWS_10_RS1) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x0185; + sc_virtual_protect = 0x00ca; + sc_open_file = 0x00f0; + sc_create_section = 0x015e; + sc_map_view_of_section = 0x00fc; + sc_unmap_view_of_section = 0x0014; + sc_query_information_process = 0x00b7; + sc_set_information_thread = 0x004c; + sc_query_virtual_memory = 0x0095; + } + else +#endif + { + sc_close = 0x000f; + sc_virtual_protect = 0x0050; + sc_open_file = 0x0033; + sc_create_section = 0x004a; + sc_map_view_of_section = 0x0028; + sc_unmap_view_of_section = 0x002a; + sc_query_information_process = 0x0019; + sc_set_information_thread = 0x000d; + sc_query_virtual_memory = 0x0023; + } + } else if (os_build_number == WINDOWS_10_RS2) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x018a; + sc_virtual_protect = 0x00cc; + sc_open_file = 0x00f2; + sc_create_section = 0x0161; + sc_map_view_of_section = 0x00fe; + sc_unmap_view_of_section = 0x0014; + sc_query_information_process = 0x00b8; + sc_set_information_thread = 0x004c; + sc_query_virtual_memory = 0x0096; + } + else +#endif + { + sc_close = 0x000f; + sc_virtual_protect = 0x0050; + sc_open_file = 0x0033; + sc_create_section = 0x004a; + sc_map_view_of_section = 0x0028; + sc_unmap_view_of_section = 0x002a; + sc_query_information_process = 0x0019; + sc_set_information_thread = 0x000d; + sc_query_virtual_memory = 0x0023; + } + } + else if (os_build_number == WINDOWS_10_RS3) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x018d; + sc_virtual_protect = 0x00ce; + sc_open_file = 0x00f4; + sc_create_section = 0x0164; + sc_map_view_of_section = 0x0101; + sc_unmap_view_of_section = 0x0014; + sc_query_information_process = 0x00b9; + sc_set_information_thread = 0x004d; + sc_query_virtual_memory = 0x0097; + } + else +#endif + { + sc_close = 0x000f; + sc_virtual_protect = 0x0050; + sc_open_file = 0x0033; + sc_create_section = 0x004a; + sc_map_view_of_section = 0x0028; + sc_unmap_view_of_section = 0x002a; + sc_query_information_process = 0x0019; + sc_set_information_thread = 0x000d; + sc_query_virtual_memory = 0x0023; + } + } + else if (os_build_number == WINDOWS_10_RS4) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x018d; + sc_virtual_protect = 0x00ce; + sc_open_file = 0x00f4; + sc_create_section = 0x0164; + sc_map_view_of_section = 0x0101; + sc_unmap_view_of_section = 0x0014; + sc_query_information_process = 0x00b9; + sc_set_information_thread = 0x004d; + sc_query_virtual_memory = 0x0097; + } + else +#endif + { + sc_close = 0x000f; + sc_virtual_protect = 0x0050; + sc_open_file = 0x0033; + sc_create_section = 0x004a; + sc_map_view_of_section = 0x0028; + sc_unmap_view_of_section = 0x002a; + sc_query_information_process = 0x0019; + sc_set_information_thread = 0x000d; + sc_query_virtual_memory = 0x0023; + } + } + else if (os_build_number == WINDOWS_10_RS5) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x018d; + sc_virtual_protect = 0x00ce; + sc_open_file = 0x00f4; + sc_create_section = 0x0163; + sc_map_view_of_section = 0x0101; + sc_unmap_view_of_section = 0x0014; + sc_query_information_process = 0x00b9; + sc_set_information_thread = 0x004d; + sc_query_virtual_memory = 0x0097; + } + else +#endif + { + sc_close = 0x000f; + sc_virtual_protect = 0x0050; + sc_open_file = 0x0033; + sc_create_section = 0x004a; + sc_map_view_of_section = 0x0028; + sc_unmap_view_of_section = 0x002a; + sc_query_information_process = 0x0019; + sc_set_information_thread = 0x000d; + sc_query_virtual_memory = 0x0023; + } + } + else if (os_build_number == WINDOWS_10_19H1) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x018d; + sc_virtual_protect = 0x00ce; + sc_open_file = 0x00f4; + sc_create_section = 0x0163; + sc_map_view_of_section = 0x0101; + sc_unmap_view_of_section = 0x0014; + sc_query_information_process = 0x00b9; + sc_set_information_thread = 0x004d; + sc_query_virtual_memory = 0x0097; + } + else +#endif + { + sc_close = 0x000f; + sc_virtual_protect = 0x0050; + sc_open_file = 0x0033; + sc_create_section = 0x004a; + sc_map_view_of_section = 0x0028; + sc_unmap_view_of_section = 0x002a; + sc_query_information_process = 0x0019; + sc_set_information_thread = 0x000d; + sc_query_virtual_memory = 0x0023; + } + } + else if (os_build_number == WINDOWS_10_19H2) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x018d; + sc_virtual_protect = 0x00ce; + sc_open_file = 0x00f4; + sc_create_section = 0x0163; + sc_map_view_of_section = 0x0101; + sc_unmap_view_of_section = 0x0014; + sc_query_information_process = 0x00b9; + sc_set_information_thread = 0x004d; + sc_query_virtual_memory = 0x0097; + } + else +#endif + { + sc_close = 0x000f; + sc_virtual_protect = 0x0050; + sc_open_file = 0x0033; + sc_create_section = 0x004a; + sc_map_view_of_section = 0x0028; + sc_unmap_view_of_section = 0x002a; + sc_query_information_process = 0x0019; + sc_set_information_thread = 0x000d; + sc_query_virtual_memory = 0x0023; + } + } + else if (os_build_number == WINDOWS_10_20H1) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x018e; + sc_virtual_protect = 0x00ce; + sc_open_file = 0x00f4; + sc_create_section = 0x0163; + sc_map_view_of_section = 0x0101; + sc_unmap_view_of_section = 0x0014; + sc_query_information_process = 0x00b9; + sc_set_information_thread = 0x004d; + sc_query_virtual_memory = 0x0097; + } + else +#endif + { + sc_close = 0x000f; + sc_virtual_protect = 0x0050; + sc_open_file = 0x0033; + sc_create_section = 0x004a; + sc_map_view_of_section = 0x0028; + sc_unmap_view_of_section = 0x002a; + sc_query_information_process = 0x0019; + sc_set_information_thread = 0x000d; + sc_query_virtual_memory = 0x0023; + } + } + else if (os_build_number == WINDOWS_10_20H2) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x018e; + sc_virtual_protect = 0x00ce; + sc_open_file = 0x00f4; + sc_create_section = 0x0163; + sc_map_view_of_section = 0x0101; + sc_unmap_view_of_section = 0x0014; + sc_query_information_process = 0x00b9; + sc_set_information_thread = 0x004d; + sc_query_virtual_memory = 0x0097; + } + else +#endif + { + sc_close = 0x000f; + sc_virtual_protect = 0x0050; + sc_open_file = 0x0033; + sc_create_section = 0x004a; + sc_map_view_of_section = 0x0028; + sc_unmap_view_of_section = 0x002a; + sc_query_information_process = 0x0019; + sc_set_information_thread = 0x000d; + sc_query_virtual_memory = 0x0023; + } + } + else if (os_build_number == WINDOWS_10_21H1) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x018e; + sc_virtual_protect = 0x00ce; + sc_open_file = 0x00f4; + sc_create_section = 0x0163; + sc_map_view_of_section = 0x0101; + sc_unmap_view_of_section = 0x0014; + sc_query_information_process = 0x00b9; + sc_set_information_thread = 0x004d; + sc_query_virtual_memory = 0x0097; + } + else +#endif + { + sc_close = 0x000f; + sc_virtual_protect = 0x0050; + sc_open_file = 0x0033; + sc_create_section = 0x004a; + sc_map_view_of_section = 0x0028; + sc_unmap_view_of_section = 0x002a; + sc_query_information_process = 0x0019; + sc_set_information_thread = 0x000d; + sc_query_virtual_memory = 0x0023; + } + } + else if (os_build_number == WINDOWS_10_21H2) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x018e; + sc_virtual_protect = 0x00ce; + sc_open_file = 0x00f4; + sc_create_section = 0x0163; + sc_map_view_of_section = 0x0101; + sc_unmap_view_of_section = 0x0014; + sc_query_information_process = 0x00b9; + sc_set_information_thread = 0x004d; + sc_query_virtual_memory = 0x0097; + } + else +#endif + { + sc_close = 0x000f; + sc_virtual_protect = 0x0050; + sc_open_file = 0x0033; + sc_create_section = 0x004a; + sc_map_view_of_section = 0x0028; + sc_unmap_view_of_section = 0x002a; + sc_query_information_process = 0x0019; + sc_set_information_thread = 0x000d; + sc_query_virtual_memory = 0x0023; + } + } + else if (os_build_number == WINDOWS_10_22H2) { +#ifndef _WIN64 + if (!is_wow64) { + sc_close = 0x018e; + sc_virtual_protect = 0x00ce; + sc_open_file = 0x00f4; + sc_create_section = 0x0163; + sc_map_view_of_section = 0x0101; + sc_unmap_view_of_section = 0x0014; + sc_query_information_process = 0x00b9; + sc_set_information_thread = 0x004d; + sc_query_virtual_memory = 0x0097; + } + else +#endif + { + sc_close = 0x000f; + sc_virtual_protect = 0x0050; + sc_open_file = 0x0033; + sc_create_section = 0x004a; + sc_map_view_of_section = 0x0028; + sc_unmap_view_of_section = 0x002a; + sc_query_information_process = 0x0019; + sc_set_information_thread = 0x000d; + sc_query_virtual_memory = 0x0023; + } + } +#ifndef _WIN64 + if (is_wow64 && sc_close) { + sc_close |= WOW64_FLAG; + sc_virtual_protect |= WOW64_FLAG | (0x01 << 24); + sc_set_information_thread |= WOW64_FLAG | (0x02 << 24); + sc_query_information_process |= WOW64_FLAG | (0x03 << 24); + sc_map_view_of_section |= WOW64_FLAG | (0x04 << 24);; + sc_unmap_view_of_section |= WOW64_FLAG | (0x05 << 24); + sc_open_file |= WOW64_FLAG | (0x06 << 24); + sc_create_section |= WOW64_FLAG | (0x07 << 24); + sc_query_virtual_memory |= WOW64_FLAG | (0x08 << 24); + } +#endif + } +#endif +#endif + + // detect a debugger +#ifdef __APPLE__ + if (data.options() & LOADER_OPTION_CHECK_DEBUGGER) { + int junk; + int mib[4]; + kinfo_proc info; + size_t size; + + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + + info.kp_proc.p_flag = 0; + + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + // Call sysctl. + + size = sizeof(info); + junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0); + + // We're being debugged if the P_TRACED flag is set. + if ((info.kp_proc.p_flag & P_TRACED) != 0) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + + // disable debugger + void *handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW); + if (handle) { + typedef int (ptrace_t)(int _request, pid_t _pid, caddr_t _addr, int _data); + ptrace_t *ptrace_ptr = reinterpret_cast<ptrace_t *>(dlsym(handle, reinterpret_cast<const char *>(FACE_GNU_PTRACE))); + if (ptrace_ptr) + ptrace_ptr(PT_DENY_ATTACH, 0, 0, 0); + dlclose(handle); + } + } +#elif defined(__unix__) + if (data.options() & LOADER_OPTION_CHECK_DEBUGGER) { + char mode[2]; + mode[0] = 'r'; mode[1] = 0; + char str[18]; + str[0] = '/'; str[1] = 'p'; str[2] = 'r'; str[3] = 'o'; str[4] = 'c'; str[5] = '/'; str[6] = 's'; str[7] = 'e'; str[8] = 'l'; str[9] = 'f'; str[10] = '/'; + str[11] = 's'; str[12] = 't'; str[13] = 'a'; str[14] = 't'; str[15] = 'u'; str[16] = 's'; str[17] = 0; + FILE *file = fopen(str, mode); + if (file) { + char data[100]; + int tracer_pid = 0; + while (fgets(data, sizeof(data), file)) { + if (data[0] == 'T' && data[1] == 'r' && data[2] == 'a' && data[3] == 'c' && data[4] == 'e' && data[5] == 'r' && data[6] == 'P' && data[7] == 'i' && data[8] == 'd' && data[9] == ':') { + char *tracer_ptr = data + 10; + // skip spaces + while (char c = *tracer_ptr) { + if (c == ' ' || c == '\t') { + tracer_ptr++; + continue; + } + else { + break; + } + } + // atoi + while (char c = *tracer_ptr++) { + if (c >= '0' && c <= '9') { + tracer_pid *= 10; + tracer_pid += c - '0'; + } + else { + if (c != '\n' && c != '\r') + tracer_pid = 0; + break; + } + } + break; + } + } + fclose(file); + + if (tracer_pid && tracer_pid != 1) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + } + } +#else +#if defined(WIN_DRIVER) +#else + if (data.options() & LOADER_OPTION_CHECK_DEBUGGER) { + if (peb->BeingDebugged) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + + if (sc_query_information_process) { + // disable InstrumentationCallback + if (peb->OSMajorVersion > 6) { + // Windows 10 + PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION info; + info.Version = 0; + info.Reserved = 0; + info.Callback = NULL; + if (tNtSetInformationProcess *set_information_process = reinterpret_cast<tNtSetInformationProcess *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_SET_INFORMATION_PROCESS_NAME), true))) + set_information_process(process, ProcessInstrumentationCallback, &info, sizeof(info)); + } + + HANDLE debug_object; + if (NT_SUCCESS(reinterpret_cast<tNtQueryInformationProcess *>(syscall | sc_query_information_process)(process, ProcessDebugPort, &debug_object, sizeof(debug_object), NULL)) && debug_object != 0) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + debug_object = 0; + if (NT_SUCCESS(reinterpret_cast<tNtQueryInformationProcess *>(syscall | sc_query_information_process)(process, ProcessDebugObjectHandle, &debug_object, sizeof(debug_object), reinterpret_cast<PULONG>(&debug_object))) + || debug_object == 0) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + + } else if (tNtQueryInformationProcess *query_information_process = reinterpret_cast<tNtQueryInformationProcess *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_QUERY_INFORMATION_PROCESS_NAME), true))) { + HANDLE debug_object; + if (NT_SUCCESS(query_information_process(process, ProcessDebugPort, &debug_object, sizeof(debug_object), NULL)) && debug_object != 0) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + if (NT_SUCCESS(query_information_process(process, ProcessDebugObjectHandle, &debug_object, sizeof(debug_object), NULL))) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + } + + // disable debugger + if (sc_set_information_thread) + reinterpret_cast<tNtSetInformationThread *>(syscall | sc_set_information_thread)(thread, ThreadHideFromDebugger, NULL, 0); + else if (tNtSetInformationThread *set_information_thread = reinterpret_cast<tNtSetInformationThread *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_SET_INFORMATION_THREAD_NAME), true))) + set_information_thread(thread, ThreadHideFromDebugger, NULL, 0); + } +#endif + +#ifdef WIN_DRIVER + if (data.options() & LOADER_OPTION_CHECK_DEBUGGER) { +#else + if (data.options() & LOADER_OPTION_CHECK_KERNEL_DEBUGGER) { +#endif + bool is_found = false; + typedef NTSTATUS (NTAPI tNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength); +#ifdef WIN_DRIVER + tNtQuerySystemInformation *nt_query_system_information = &NtQuerySystemInformation; +#else + tNtQuerySystemInformation *nt_query_system_information = reinterpret_cast<tNtQuerySystemInformation *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_QUERY_INFORMATION_NAME), true)); + if (nt_query_system_information) { +#endif + SYSTEM_KERNEL_DEBUGGER_INFORMATION info; + NTSTATUS status = nt_query_system_information(SystemKernelDebuggerInformation, &info, sizeof(info), NULL); + if (NT_SUCCESS(status) && info.DebuggerEnabled && !info.DebuggerNotPresent) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + + SYSTEM_MODULE_INFORMATION *buffer = NULL; + ULONG buffer_size = 0; + status = nt_query_system_information(SystemModuleInformation, &buffer, 0, &buffer_size); + if (buffer_size) { + buffer = reinterpret_cast<SYSTEM_MODULE_INFORMATION *>(LoaderAlloc(buffer_size * 2)); + if (buffer) { + status = nt_query_system_information(SystemModuleInformation, buffer, buffer_size * 2, NULL); + if (NT_SUCCESS(status)) { + for (size_t i = 0; i < buffer->Count && !is_found; i++) { + SYSTEM_MODULE_ENTRY *module_entry = &buffer->Module[i]; + for (size_t j = 0; j < 5 ; j++) { + const char *module_name; + switch (j) { + case 0: + module_name = reinterpret_cast<const char *>(FACE_SICE_NAME); + break; + case 1: + module_name = reinterpret_cast<const char *>(FACE_SIWVID_NAME); + break; + case 2: + module_name = reinterpret_cast<const char *>(FACE_NTICE_NAME); + break; + case 3: + module_name = reinterpret_cast<const char *>(FACE_ICEEXT_NAME); + break; + case 4: + module_name = reinterpret_cast<const char *>(FACE_SYSER_NAME); + break; + } + if (Loader_stricmp(module_name, module_entry->Name + module_entry->PathLength, true) == 0) { + is_found = true; + break; + } + } + } + } + LoaderFree(buffer); + } + } +#ifndef WIN_DRIVER + } +#endif + if (is_found) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + } +#endif + + // check header and loader CRC + if (data.loader_crc_info_size()) { + uint32_t loader_crc_info_size = *reinterpret_cast<uint32_t *>(image_base + data.loader_crc_info_size()); + uint32_t loader_crc_info_hash = *reinterpret_cast<uint32_t *>(image_base + data.loader_crc_info_hash()); + bool is_valid_crc = true; + CRCValueCryptor crc_cryptor; + + if (loader_crc_info_hash != CalcCRC(image_base + data.loader_crc_info(), loader_crc_info_size)) + is_valid_crc = false; + for (i = 0; i < loader_crc_info_size; i += sizeof(CRC_INFO)) { + CRC_INFO crc_info = *reinterpret_cast<CRC_INFO *>(image_base + data.loader_crc_info() + i); + crc_info.Address = crc_cryptor.Decrypt(crc_info.Address); + crc_info.Size = crc_cryptor.Decrypt(crc_info.Size); + crc_info.Hash = crc_cryptor.Decrypt(crc_info.Hash); + + if (crc_info.Hash != CalcCRC(image_base + crc_info.Address, crc_info.Size)) + is_valid_crc = false; + } + + if (!is_valid_crc) { + if (data.options() & LOADER_OPTION_CHECK_PATCH) { + LoaderMessage(mtFileCorrupted); + return LOADER_ERROR; + } + tmp_loader_data->set_is_patch_detected(true); + } + + tmp_loader_data->set_loader_crc_size(loader_crc_info_size); + tmp_loader_data->set_loader_crc_hash(loader_crc_info_hash); + + if (data.options() & LOADER_OPTION_CHECK_DEBUGGER) { + // check debugger again +#ifdef VMP_GNU +#elif defined(WIN_DRIVER) +#else + if (sc_query_information_process) { + HANDLE debug_object; + if (NT_SUCCESS(reinterpret_cast<tNtQueryInformationProcess *>(syscall | sc_query_information_process)(process, ProcessDebugPort, &debug_object, sizeof(debug_object), NULL)) && debug_object != 0) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + } + if (sc_set_information_thread) + reinterpret_cast<tNtSetInformationThread *>(syscall | sc_set_information_thread)(thread, ThreadHideFromDebugger, NULL, 0); +#endif + } + } + + // check file CRC + if (data.file_crc_info_size()) { + uint32_t file_crc_info_size = *reinterpret_cast<uint32_t *>(image_base + data.file_crc_info_size()); +#ifdef VMP_GNU + Dl_info info; + if (dladdr(reinterpret_cast<const void *>(&LzmaDecode), &info)) { + int file_handle = open(info.dli_fname, O_RDONLY); + if (file_handle != -1) { + FILE_CRC_INFO *file_info = reinterpret_cast<FILE_CRC_INFO *>(image_base + data.file_crc_info()); + + size_t file_size = lseek(file_handle, 0, SEEK_END); + bool is_valid_crc; + if (file_size < file_info->FileSize) { + is_valid_crc = false; + } else { + is_valid_crc = true; + uint8_t *file_view = reinterpret_cast<uint8_t *>(mmap(0, file_size, PROT_READ, MAP_SHARED, file_handle, 0)); + if (file_view != MAP_FAILED) { + size_t arch_offset = 0; +#ifdef __APPLE__ + fat_header *fat = reinterpret_cast<fat_header*>(file_view); + if (fat->magic == FAT_MAGIC || fat->magic == FAT_CIGAM) { + fat_arch *arch = reinterpret_cast<fat_arch*>(file_view + sizeof(fat_header)); + mach_header *mach = reinterpret_cast<mach_header*>(image_base); + for (i = 0; i < fat->nfat_arch; i++) { + fat_arch cur_arch = arch[i]; + if (fat->magic == FAT_CIGAM) { + cur_arch.cputype = __builtin_bswap32(cur_arch.cputype); + cur_arch.cpusubtype = __builtin_bswap32(cur_arch.cpusubtype); + cur_arch.offset = __builtin_bswap32(cur_arch.offset); + cur_arch.size = __builtin_bswap32(cur_arch.size); + } + if (cur_arch.cputype == mach->cputype && cur_arch.cpusubtype == mach->cpusubtype) { + arch_offset = cur_arch.offset; + if (cur_arch.size < file_info->FileSize) + is_valid_crc = false; + break; + } + } + } +#endif + if (is_valid_crc) { + CRCValueCryptor crc_cryptor; + for (i = sizeof(FILE_CRC_INFO); i < file_crc_info_size; i += sizeof(CRC_INFO)) { + CRC_INFO crc_info = *reinterpret_cast<CRC_INFO *>(image_base + data.file_crc_info() + i); + crc_info.Address = crc_cryptor.Decrypt(crc_info.Address); + crc_info.Size = crc_cryptor.Decrypt(crc_info.Size); + crc_info.Hash = crc_cryptor.Decrypt(crc_info.Hash); + + if (crc_info.Hash != CalcCRC(file_view + arch_offset + crc_info.Address, crc_info.Size)) + is_valid_crc = false; + } + } + munmap(file_view, file_size); + } + } + close(file_handle); + + if (!is_valid_crc) { + if (data.options() & LOADER_OPTION_CHECK_PATCH) { + LoaderMessage(mtFileCorrupted); + return LOADER_ERROR; + } + tmp_loader_data->set_is_patch_detected(true); + } + } + } +#elif defined(WIN_DRIVER) + // FIXME +#else + wchar_t file_name[MAX_PATH]; + if (GetModuleFileNameW(reinterpret_cast<HMODULE>(image_base), file_name + 6, _countof(file_name) - 6)) { + wchar_t *nt_file_name; + if (file_name[6] == '\\' && file_name[7] == '\\') { + nt_file_name = file_name; + nt_file_name[0] = '\\'; + nt_file_name[1] = '?'; + nt_file_name[2] = '?'; + nt_file_name[3] = '\\'; + nt_file_name[4] = 'U'; + nt_file_name[5] = 'N'; + nt_file_name[6] = 'C'; + } else { + nt_file_name = file_name + 2; + nt_file_name[0] = '\\'; + nt_file_name[1] = '?'; + nt_file_name[2] = '?'; + nt_file_name[3] = '\\'; + } + + if (sc_open_file) { + HANDLE file_handle; + OBJECT_ATTRIBUTES object_attributes; + IO_STATUS_BLOCK io_status_block; + UNICODE_STRING str; + + InitUnicodeString(&str, nt_file_name); + InitializeObjectAttributes(&object_attributes, &str, 0, NULL, NULL); + if (NT_SUCCESS(reinterpret_cast<tNtOpenFile *>(syscall | sc_open_file)(&file_handle, GENERIC_READ | SYNCHRONIZE | FILE_READ_ATTRIBUTES, &object_attributes, &io_status_block, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT))) { + FILE_CRC_INFO *file_info = reinterpret_cast<FILE_CRC_INFO *>(image_base + data.file_crc_info()); + bool is_valid_crc = true; + HANDLE file_map; + InitializeObjectAttributes(&object_attributes, NULL, 0, NULL, NULL); + if (NT_SUCCESS(reinterpret_cast<tNtCreateSection *>(syscall | sc_create_section)(&file_map, SECTION_MAP_READ, &object_attributes, NULL, PAGE_READONLY, SEC_COMMIT, file_handle))) { + void *file_view = NULL; + SIZE_T file_size = 0; + LARGE_INTEGER offset; + offset.LowPart = 0; + offset.HighPart = 0; + if (NT_SUCCESS(reinterpret_cast<tNtMapViewOfSection *>(syscall | sc_map_view_of_section)(file_map, process, &file_view, NULL, 0, &offset, &file_size, ViewShare, 0, PAGE_READONLY))) { + if (file_size < file_info->FileSize) + is_valid_crc = false; + else { + CRCValueCryptor crc_cryptor; + for (i = sizeof(FILE_CRC_INFO); i < file_crc_info_size; i += sizeof(CRC_INFO)) { + CRC_INFO crc_info = *reinterpret_cast<CRC_INFO *>(image_base + data.file_crc_info() + i); + crc_info.Address = crc_cryptor.Decrypt(crc_info.Address); + crc_info.Size = crc_cryptor.Decrypt(crc_info.Size); + crc_info.Hash = crc_cryptor.Decrypt(crc_info.Hash); + + if (crc_info.Hash != CalcCRC(static_cast<uint8_t *>(file_view) + crc_info.Address, crc_info.Size)) + is_valid_crc = false; + } + } + reinterpret_cast<tNtUnmapViewOfSection *>(syscall | sc_unmap_view_of_section)(process, file_view); + } + reinterpret_cast<tNtClose *>(syscall | sc_close)(file_map); + } + reinterpret_cast<tNtClose *>(syscall | sc_close)(file_handle); + + if (!is_valid_crc) { + if (data.options() & LOADER_OPTION_CHECK_PATCH) { + LoaderMessage(mtFileCorrupted); + return LOADER_ERROR; + } + tmp_loader_data->set_is_patch_detected(true); + } + } + } + else { + tNtOpenFile *open_file = reinterpret_cast<tNtOpenFile *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_OPEN_FILE_NAME), true)); + tNtCreateSection *create_section = reinterpret_cast<tNtCreateSection *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_CREATE_SECTION_NAME), true)); + tNtMapViewOfSection *map_view_of_section = reinterpret_cast<tNtMapViewOfSection *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_MAP_VIEW_OF_SECTION), true)); + tNtUnmapViewOfSection *unmap_view_of_section = reinterpret_cast<tNtUnmapViewOfSection *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_UNMAP_VIEW_OF_SECTION), true)); + tNtClose *close = reinterpret_cast<tNtClose *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_CLOSE), true)); + + if (!create_section + || !open_file + || !map_view_of_section + || !unmap_view_of_section + || !close) { + LoaderMessage(mtInitializationError, INTERNAL_GPA_ERROR); + return LOADER_ERROR; + } + + // check breakpoint + uint8_t *ckeck_list[] = { reinterpret_cast<uint8_t*>(create_section), + reinterpret_cast<uint8_t*>(open_file), + reinterpret_cast<uint8_t*>(map_view_of_section), + reinterpret_cast<uint8_t*>(unmap_view_of_section), + reinterpret_cast<uint8_t*>(close) }; + for (i = 0; i < _countof(ckeck_list); i++) { + if (*ckeck_list[i] == 0xcc) { + if (data.options() & LOADER_OPTION_CHECK_DEBUGGER) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + tmp_loader_data->set_is_debugger_detected(true); + } + } + + HANDLE file_handle; + OBJECT_ATTRIBUTES object_attributes; + IO_STATUS_BLOCK io_status_block; + UNICODE_STRING str; + + InitUnicodeString(&str, nt_file_name); + InitializeObjectAttributes(&object_attributes, &str, 0, NULL, NULL); + if (NT_SUCCESS(open_file(&file_handle, GENERIC_READ | SYNCHRONIZE | FILE_READ_ATTRIBUTES, &object_attributes, &io_status_block, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT))) { + FILE_CRC_INFO *file_info = reinterpret_cast<FILE_CRC_INFO *>(image_base + data.file_crc_info()); + bool is_valid_crc = true; + HANDLE file_map; + InitializeObjectAttributes(&object_attributes, NULL, 0, NULL, NULL); + if (NT_SUCCESS(create_section(&file_map, SECTION_MAP_READ, &object_attributes, NULL, PAGE_READONLY, SEC_COMMIT, file_handle))) { + void *file_view = NULL; + SIZE_T file_size = 0; + LARGE_INTEGER offset; + offset.LowPart = 0; + offset.HighPart = 0; + if (NT_SUCCESS(map_view_of_section(file_map, process, &file_view, NULL, 0, &offset, &file_size, ViewShare, 0, PAGE_READONLY))) { + if (file_size < file_info->FileSize) + is_valid_crc = false; + else { + CRCValueCryptor crc_cryptor; + for (i = sizeof(FILE_CRC_INFO); i < file_crc_info_size; i += sizeof(CRC_INFO)) { + CRC_INFO crc_info = *reinterpret_cast<CRC_INFO *>(image_base + data.file_crc_info() + i); + crc_info.Address = crc_cryptor.Decrypt(crc_info.Address); + crc_info.Size = crc_cryptor.Decrypt(crc_info.Size); + crc_info.Hash = crc_cryptor.Decrypt(crc_info.Hash); + + if (crc_info.Hash != CalcCRC(static_cast<uint8_t *>(file_view) + crc_info.Address, crc_info.Size)) + is_valid_crc = false; + } + } + unmap_view_of_section(process, file_view); + } + close(file_map); + } + close(file_handle); + + if (!is_valid_crc) { + if (data.options() & LOADER_OPTION_CHECK_PATCH) { + LoaderMessage(mtFileCorrupted); + return LOADER_ERROR; + } + tmp_loader_data->set_is_patch_detected(true); + } + } + } + } +#endif + } + + // setup WRITABLE flag for memory pages + uint32_t data_section_info_size = data.section_info_size(); + uint32_t data_section_info = data.section_info(); +#ifdef VMP_GNU + for (i = 0; i < data_section_info_size; i += sizeof(SECTION_INFO)) { + SECTION_INFO *section_info = reinterpret_cast<SECTION_INFO *>(image_base + data_section_info + i); + + int protect = PROT_READ | PROT_WRITE; + if (section_info->Type & PROT_EXEC) + protect |= PROT_EXEC; + if (mprotect(image_base + section_info->Address, section_info->Size, protect) != 0) { + LoaderMessage(mtInitializationError, VIRTUAL_PROTECT_ERROR); + return LOADER_ERROR; + } + } +#elif defined(WIN_DRIVER) + ULONG size = 0; + for (i = 0; i < data_section_info_size; i += sizeof(SECTION_INFO)) { + SECTION_INFO *section_info = reinterpret_cast<SECTION_INFO *>(image_base + data_section_info + i); + + if (section_info->Address + section_info->Size > size) + size = section_info->Address + section_info->Size; + } + PMDL mdl = NULL; + if (size) { + mdl = IoAllocateMdl(image_base, size, FALSE, FALSE, NULL); + if (!mdl) { + LoaderMessage(mtInitializationError, VIRTUAL_PROTECT_ERROR); + return LOADER_ERROR; + } + __try { + MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess); + } + __except (EXCEPTION_EXECUTE_HANDLER) { + IoFreeMdl(mdl); + LoaderMessage(mtInitializationError, VIRTUAL_PROTECT_ERROR); + return LOADER_ERROR; + } + dst_image_base = static_cast<uint8_t *>(MmGetSystemAddressForMdlSafe(mdl, (MM_PAGE_PRIORITY)FACE_DEFAULT_MDL_PRIORITY)); + if (!dst_image_base) { + MmUnlockPages(mdl); + IoFreeMdl(mdl); + LoaderMessage(mtInitializationError, VIRTUAL_PROTECT_ERROR); + return LOADER_ERROR; + } + } +#else + tNtProtectVirtualMemory *virtual_protect = NULL; + if (sc_virtual_protect) { + for (i = 0; i < data_section_info_size; i += sizeof(SECTION_INFO)) { + SECTION_INFO *section_info = reinterpret_cast<SECTION_INFO *>(image_base + data_section_info + i); + + DWORD protect, old_protect; + protect = (section_info->Type & IMAGE_SCN_MEM_EXECUTE) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; + void *address = image_base + section_info->Address; + SIZE_T size = section_info->Size; + if (!NT_SUCCESS(reinterpret_cast<tNtProtectVirtualMemory *>(syscall | sc_virtual_protect)(process, &address, &size, protect, &old_protect))) { + LoaderMessage(mtInitializationError, VIRTUAL_PROTECT_ERROR); + return LOADER_ERROR; + } + if (old_protect & PAGE_GUARD) { + if (data.options() & LOADER_OPTION_CHECK_DEBUGGER) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + tmp_loader_data->set_is_debugger_detected(true); + } + } + } else { + virtual_protect = reinterpret_cast<tNtProtectVirtualMemory *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_VIRTUAL_PROTECT_NAME), true)); + if (!virtual_protect) { + LoaderMessage(mtInitializationError, INTERNAL_GPA_ERROR); + return LOADER_ERROR; + } + // check breakpoint + if (*reinterpret_cast<uint8_t*>(virtual_protect) == 0xcc) { + if (data.options() & LOADER_OPTION_CHECK_DEBUGGER) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + tmp_loader_data->set_is_debugger_detected(true); + } + for (i = 0; i < data_section_info_size; i += sizeof(SECTION_INFO)) { + SECTION_INFO *section_info = reinterpret_cast<SECTION_INFO *>(image_base + data_section_info + i); + + DWORD protect, old_protect; + protect = (section_info->Type & IMAGE_SCN_MEM_EXECUTE) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; + void *address = image_base + section_info->Address; + SIZE_T size = section_info->Size; + if (!NT_SUCCESS(virtual_protect(process, &address, &size, protect, &old_protect))) { + LoaderMessage(mtInitializationError, VIRTUAL_PROTECT_ERROR); + return LOADER_ERROR; + } + if (old_protect & PAGE_GUARD) { + if (data.options() & LOADER_OPTION_CHECK_DEBUGGER) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + tmp_loader_data->set_is_debugger_detected(true); + } + } + } +#endif + + // unpack regions + if (data.packer_info_size()) { +#ifdef VMP_GNU +#elif defined(WIN_DRIVER) +#else + uint32_t tls_index = 0; + if (data.tls_index_info()) + tls_index = *reinterpret_cast<uint32_t *>(image_base + data.tls_index_info()); +#endif + PACKER_INFO *packer_info = reinterpret_cast<PACKER_INFO *>(image_base + data.packer_info()); + CLzmaDecoderState state; + if (LzmaDecodeProperties(&state.Properties, image_base + packer_info->Src, packer_info->Dst) != LZMA_RESULT_OK) { + LoaderMessage(mtInitializationError, UNPACKER_ERROR); + return LOADER_ERROR; + } + state.Probs = (CProb *)LoaderAlloc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb)); + if (state.Probs == 0) { + LoaderMessage(mtInitializationError, UNPACKER_ERROR); + return LOADER_ERROR; + } + SizeT src_processed_size; + SizeT dst_processed_size; + for (i = sizeof(PACKER_INFO); i < data.packer_info_size(); i += sizeof(PACKER_INFO)) { + packer_info = reinterpret_cast<PACKER_INFO *>(image_base + data.packer_info() + i); + if (LzmaDecode(&state, image_base + packer_info->Src, -1, &src_processed_size, dst_image_base + packer_info->Dst, -1, &dst_processed_size) != LZMA_RESULT_OK) { + LoaderFree(state.Probs); + LoaderMessage(mtInitializationError, UNPACKER_ERROR); + return LOADER_ERROR; + } + } + LoaderFree(state.Probs); +#ifdef VMP_GNU +#elif defined(WIN_DRIVER) +#else + if (data.tls_index_info()) + *reinterpret_cast<uint32_t *>(dst_image_base + data.tls_index_info()) = tls_index; +#endif + } + + // setup fixups + if (delta_base != 0) + LoaderProcessFixups(delta_base, data.fixup_info(), data.fixup_info_size(), image_base, dst_image_base); + + // setup IAT + for (i = 0; i < data.iat_info_size(); i += sizeof(IAT_INFO)) { + IAT_INFO *iat_info = reinterpret_cast<IAT_INFO *>(image_base + data.iat_info() + i); + __movsb(iat_info->Dst + dst_image_base, iat_info->Src + image_base, iat_info->Size); + } + + // setup import +#ifdef VMP_GNU +#else + for (i = 0; i < data.import_info_size(); i += sizeof(DLL_INFO)) { + DLL_INFO *dll_info = reinterpret_cast<DLL_INFO *>(image_base + data.import_info() + i); + const char *dll_name = reinterpret_cast<const char *>(image_base + dll_info->Name); + HMODULE h = LoaderGetModuleHandleEnc(dll_name); + + for (IMPORT_INFO *import_info = reinterpret_cast<IMPORT_INFO *>(dll_info + 1); import_info->Name != 0; import_info++, i += sizeof(IMPORT_INFO)) { + const char *api_name; + if (import_info->Name & IMAGE_ORDINAL_FLAG32) { + api_name = LPCSTR(INT_PTR((IMAGE_ORDINAL32(import_info->Name)))); + } else { + api_name = LPCSTR(INT_PTR((image_base + import_info->Name))); + } + + void *p = LoaderGetProcAddress(h, api_name, true); + if (!p) { +#ifndef WIN_DRIVER + ULONG error_mode = 0; + if (tNtQueryInformationProcess *query_information_process = reinterpret_cast<tNtQueryInformationProcess *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_QUERY_INFORMATION_PROCESS_NAME), true))) { + query_information_process(process, ProcessDefaultHardErrorMode, &error_mode, sizeof(error_mode), NULL); + } + if (error_mode & SEM_FAILCRITICALERRORS) + return LOADER_ERROR; +#endif + LoaderMessage((import_info->Name & IMAGE_ORDINAL_FLAG32) ? mtOrdinalNotFound : mtProcNotFound, api_name, dll_name); + return LOADER_ERROR; + } + + *(reinterpret_cast<void **>(dst_image_base + import_info->Address)) = reinterpret_cast<uint8_t *>(p) - import_info->Key; + } + + i += sizeof(uint32_t); + } +#endif + + // setup internal import + for (i = 0; i < data.internal_import_info_size(); i += sizeof(IMPORT_INFO)) { + IMPORT_INFO *import_info = reinterpret_cast<IMPORT_INFO *>(image_base + data.internal_import_info() + i); + *(reinterpret_cast<void **>(dst_image_base + import_info->Address)) = import_info->Name + dst_image_base - import_info->Key; + } + + // setup relocations + for (i = 0; i < data.relocation_info_size(); i += sizeof(RELOCATION_INFO)) { + RELOCATION_INFO *relocation_info = reinterpret_cast<RELOCATION_INFO *>(image_base + data.relocation_info() + i); + uint8_t *address = dst_image_base + relocation_info->Address; + uint8_t *source = dst_image_base + relocation_info->Source; +#ifdef __unix__ + if (relocation_info->Type == 0) { + // R_386_IRELATIVE + *reinterpret_cast<size_t *>(address) = reinterpret_cast<size_t(*)(void)>(source)(); + } else if (relocation_info->Type == 1) { + // R_386_PC32 + *reinterpret_cast<uint32_t *>(address) += *reinterpret_cast<uint32_t *>(source) - static_cast<uint32_t>(reinterpret_cast<size_t>(address)); + } +#else + if (relocation_info->Type == 0) { + *reinterpret_cast<size_t *>(address) += relocation_info->Source; + } else { + size_t data = 0; +#if defined(_M_X64) || defined(__amd64__) + if (relocation_info->Type == 4) + data = *reinterpret_cast<int64_t *>(address); + else +#endif + if (relocation_info->Type == 3) + data = *reinterpret_cast<int32_t *>(address); + else if (relocation_info->Type == 2) + data = *reinterpret_cast<int16_t *>(address); + else if (relocation_info->Type == 1) + data = *reinterpret_cast<int8_t *>(address); + + data -= reinterpret_cast<size_t>(source); + data += *reinterpret_cast<size_t *>(source); + +#if defined(_M_X64) || defined(__amd64__) + if (relocation_info->Type == 4) + *reinterpret_cast<uint64_t *>(address) = static_cast<uint64_t>(data); + else +#endif + if (relocation_info->Type == 3) + *reinterpret_cast<uint32_t *>(address) = static_cast<uint32_t>(data); + else if (relocation_info->Type == 2) + *reinterpret_cast<uint16_t *>(address) = static_cast<uint16_t>(data); + else if (relocation_info->Type == 1) + *reinterpret_cast<uint8_t *>(address) = static_cast<uint8_t>(data); + } +#endif + } + +#ifndef VMP_GNU +#ifndef WIN_DRIVER + if (data.options() & LOADER_OPTION_CHECK_DEBUGGER) { + typedef BOOL (WINAPI tCloseHandle)(HANDLE hObject); + tCloseHandle *close_handle = reinterpret_cast<tCloseHandle *>(LoaderGetProcAddress(kernel32, reinterpret_cast<const char *>(FACE_CLOSE_HANDLE_NAME), true)); + if (close_handle) { + __try { + if (close_handle(HANDLE(INT_PTR(0xDEADC0DE)))) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + } __except(EXCEPTION_EXECUTE_HANDLER) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + } + + size_t drx; + uint64_t val; + CONTEXT *ctx; + __try { + __writeeflags(__readeflags() | 0x100); + val = __rdtsc(); + __nop(); + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } __except(ctx = (GetExceptionInformation())->ContextRecord, + drx = (ctx->ContextFlags & CONTEXT_DEBUG_REGISTERS) ? ctx->Dr0 | ctx->Dr1 | ctx->Dr2 | ctx->Dr3 : 0, + EXCEPTION_EXECUTE_HANDLER) { + if (drx) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + } + } +#endif +#endif + + // detect a virtual machine + if (data.options() & LOADER_OPTION_CHECK_VIRTUAL_MACHINE) { + int cpu_info[4]; + __cpuid(cpu_info, 1); + if ((cpu_info[2] >> 31) & 1) { + // hypervisor found + bool is_found = true; +#ifndef VMP_GNU + // check Hyper-V root partition + cpu_info[1] = 0; + cpu_info[2] = 0; + cpu_info[3] = 0; + __cpuid(cpu_info, 0x40000000); + if (cpu_info[1] == 0x7263694d && cpu_info[2] == 0x666f736f && cpu_info[3] == 0x76482074) { // "Microsoft Hv" + cpu_info[1] = 0; + __cpuid(cpu_info, 0x40000003); + if (cpu_info[1] & 1) + is_found = false; + } +#endif + if (is_found) { + LoaderMessage(mtVirtualMachineFound); + return LOADER_ERROR; + } + } + else { +#ifdef __APPLE__ + // FIXME +#elif defined(__unix__) + bool is_found = false; + char mode[2]; + mode[0] = 'r'; mode[1] = 0; + char str[39]; + str[0] = '/'; str[1] = 's'; str[2] = 'y'; str[3] = 's'; str[4] = '/'; str[5] = 'd'; str[6] = 'e'; str[7] = 'v'; str[8] = 'i'; str[9] = 'c'; str[10] = 'e'; + str[11] = 's'; str[12] = '/'; str[13] = 'v'; str[14] = 'i'; str[15] = 'r'; str[16] = 't'; str[17] = 'u'; str[18] = 'a'; str[19] = 'l'; str[20] = '/'; + str[21] = 'd'; str[22] = 'm'; str[23] = 'i'; str[24] = '/'; str[25] = 'i'; str[26] = 'd'; str[27] = '/'; str[28] = 's'; str[29] = 'y'; str[30] = 's'; + str[31] = '_'; str[32] = 'v'; str[33] = 'e'; str[34] = 'n'; str[35] = 'd'; str[36] = 'o'; str[37] = 'r'; str[38] = 0; + FILE *fsys_vendor = fopen(str, mode); + if (fsys_vendor) { + char sys_vendor[256] = { 0 }; + fgets(sys_vendor, sizeof(sys_vendor), fsys_vendor); + fclose(fsys_vendor); + if (LoaderFindFirmwareVendor(reinterpret_cast<uint8_t *>(sys_vendor), sizeof(sys_vendor))) + is_found = true; + } + + if (is_found) { + LoaderMessage(mtVirtualMachineFound); + return LOADER_ERROR; + } +#else + uint8_t mem_val; + uint64_t val; + __try { + // set T flag + __writeeflags(__readeflags() | 0x100); + val = __rdtsc(); + __nop(); + if (data.options() & LOADER_OPTION_CHECK_DEBUGGER) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + tmp_loader_data->set_is_debugger_detected(true); + } + __except (mem_val = *static_cast<uint8_t *>((GetExceptionInformation())->ExceptionRecord->ExceptionAddress), EXCEPTION_EXECUTE_HANDLER) { + if (mem_val != 0x90) { + LoaderMessage(mtVirtualMachineFound); + return LOADER_ERROR; + } + } + + __try { + // set T flag + __writeeflags(__readeflags() | 0x100); + __cpuid(cpu_info, 1); + __nop(); + if (data.options() & LOADER_OPTION_CHECK_DEBUGGER) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + tmp_loader_data->set_is_debugger_detected(true); + } + __except (mem_val = *static_cast<uint8_t *>((GetExceptionInformation())->ExceptionRecord->ExceptionAddress), EXCEPTION_EXECUTE_HANDLER) { + if (mem_val != 0x90) { + LoaderMessage(mtVirtualMachineFound); + return LOADER_ERROR; + } + } + +#ifdef WIN_DRIVER + bool is_found = false; + ULONG table_size = 0x1000; + SYSTEM_FIRMWARE_TABLE_INFORMATION *table = static_cast<SYSTEM_FIRMWARE_TABLE_INFORMATION *>(LoaderAlloc(table_size)); + table->Action = SystemFirmwareTable_Get; + table->ProviderSignature = 'FIRM'; + table->TableID = 0xc0000; + table->TableBufferLength = table_size; + NTSTATUS status = NtQuerySystemInformation(SystemFirmwareTableInformation, table, table_size, &table_size); + if (status == STATUS_BUFFER_TOO_SMALL) { + LoaderFree(table); + + table = static_cast<SYSTEM_FIRMWARE_TABLE_INFORMATION *>(LoaderAlloc(table_size)); + table->Action = SystemFirmwareTable_Get; + table->ProviderSignature = 'FIRM'; + table->TableID = 0xc0000; + table->TableBufferLength = table_size; + } + status = NtQuerySystemInformation(SystemFirmwareTableInformation, table, table_size, &table_size); + if (NT_SUCCESS(status)) { + if (LoaderFindFirmwareVendor(reinterpret_cast<uint8_t *>(table), table_size)) + is_found = true; + } + LoaderFree(table); + if (is_found) { + LoaderMessage(mtVirtualMachineFound); + return LOADER_ERROR; + } +#else + bool is_found = false; + typedef UINT(WINAPI tEnumSystemFirmwareTables)(DWORD FirmwareTableProviderSignature, PVOID pFirmwareTableEnumBuffer, DWORD BufferSize); + typedef UINT(WINAPI tGetSystemFirmwareTable)(DWORD FirmwareTableProviderSignature, DWORD FirmwareTableID, PVOID pFirmwareTableBuffer, DWORD BufferSize); + tEnumSystemFirmwareTables *enum_system_firmware_tables = reinterpret_cast<tEnumSystemFirmwareTables *>(LoaderGetProcAddress(kernel32, reinterpret_cast<const char *>(FACE_ENUM_SYSTEM_FIRMWARE_NAME), true)); + tGetSystemFirmwareTable *get_system_firmware_table = reinterpret_cast<tGetSystemFirmwareTable *>(LoaderGetProcAddress(kernel32, reinterpret_cast<const char *>(FACE_GET_SYSTEM_FIRMWARE_NAME), true)); + if (enum_system_firmware_tables && get_system_firmware_table) { + UINT tables_size = enum_system_firmware_tables('FIRM', NULL, 0); + if (tables_size) { + DWORD *tables = static_cast<DWORD *>(LoaderAlloc(tables_size)); + enum_system_firmware_tables('FIRM', tables, tables_size); + for (size_t i = 0; i < tables_size / sizeof(DWORD); i++) { + UINT data_size = get_system_firmware_table('FIRM', tables[i], NULL, 0); + if (data_size) { + uint8_t *data = static_cast<uint8_t *>(LoaderAlloc(data_size)); + get_system_firmware_table('FIRM', tables[i], data, data_size); + if (LoaderFindFirmwareVendor(data, data_size)) + is_found = true; + LoaderFree(data); + } + } + LoaderFree(tables); + } + } + else { + tNtOpenSection *open_section = reinterpret_cast<tNtOpenSection *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_OPEN_SECTION_NAME), true)); + tNtMapViewOfSection *map_view_of_section = reinterpret_cast<tNtMapViewOfSection *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_MAP_VIEW_OF_SECTION), true)); + tNtUnmapViewOfSection *unmap_view_of_section = reinterpret_cast<tNtUnmapViewOfSection *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_UNMAP_VIEW_OF_SECTION), true)); + tNtClose *close = reinterpret_cast<tNtClose *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_CLOSE), true)); + + if (open_section && map_view_of_section && unmap_view_of_section && close) { + HANDLE physical_memory = NULL; + UNICODE_STRING str; + OBJECT_ATTRIBUTES attrs; + + wchar_t buf[] = { '\\','d','e','v','i','c','e','\\','p','h','y','s','i','c','a','l','m','e','m','o','r','y',0 }; + + InitUnicodeString(&str, buf); + InitializeObjectAttributes(&attrs, &str, OBJ_CASE_INSENSITIVE, NULL, NULL); + NTSTATUS status = open_section(&physical_memory, SECTION_MAP_READ, &attrs); + if (NT_SUCCESS(status)) { + void *data = NULL; + SIZE_T data_size = 0x10000; + LARGE_INTEGER offset; + offset.QuadPart = 0xc0000; + + status = map_view_of_section(physical_memory, process, &data, NULL, data_size, &offset, &data_size, ViewShare, 0, PAGE_READONLY); + if (NT_SUCCESS(status)) { + if (LoaderFindFirmwareVendor(static_cast<uint8_t *>(data), data_size)) + is_found = true; + unmap_view_of_section(process, data); + } + close(physical_memory); + } + } + } + if (is_found) { + LoaderMessage(mtVirtualMachineFound); + return LOADER_ERROR; + } + + if (LoaderGetModuleHandleEnc(reinterpret_cast<const char *>(FACE_SBIEDLL_NAME))) { + LoaderMessage(mtVirtualMachineFound); + return LOADER_ERROR; + } +#endif +#endif + } + } + + // check memory CRC + if (data.memory_crc_info_size()) { + bool is_valid_crc = true; + +#ifndef DEMO +#ifdef VMP_GNU +#elif defined(WIN_DRIVER) +#else + if (sc_query_virtual_memory) { + MEMORY_BASIC_INFORMATION memory_info; + + // check tmp_loader_data + NTSTATUS status = reinterpret_cast<tNtQueryVirtualMemory *>(syscall | sc_query_virtual_memory)(process, tmp_loader_data, MemoryBasicInformation, &memory_info, sizeof(memory_info), NULL); + if (NT_SUCCESS(status) && memory_info.AllocationBase == image_base) + is_valid_crc = false; + + // check memory after image + IMAGE_DOS_HEADER *dos_header = reinterpret_cast<IMAGE_DOS_HEADER *>(image_base); + IMAGE_NT_HEADERS *pe_header = reinterpret_cast<IMAGE_NT_HEADERS *>(image_base + dos_header->e_lfanew); + status = reinterpret_cast<tNtQueryVirtualMemory *>(syscall | sc_query_virtual_memory)(process, image_base + pe_header->OptionalHeader.SizeOfImage, MemoryBasicInformation, &memory_info, sizeof(memory_info), NULL); + if (NT_SUCCESS(status) && memory_info.AllocationBase == image_base) + is_valid_crc = false; + } else { + tNtQueryVirtualMemory *query_virtual_memory = reinterpret_cast<tNtQueryVirtualMemory *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_QUERY_VIRTUAL_MEMORY_NAME), true)); + if (query_virtual_memory) { + MEMORY_BASIC_INFORMATION memory_info; + + // check tmp_loader_data + NTSTATUS status = query_virtual_memory(process, tmp_loader_data, MemoryBasicInformation, &memory_info, sizeof(memory_info), NULL); + if (NT_SUCCESS(status) && memory_info.AllocationBase == image_base) + is_valid_crc = false; + + // check memory after image + IMAGE_DOS_HEADER *dos_header = reinterpret_cast<IMAGE_DOS_HEADER *>(image_base); + IMAGE_NT_HEADERS *pe_header = reinterpret_cast<IMAGE_NT_HEADERS *>(image_base + dos_header->e_lfanew); + status = query_virtual_memory(process, image_base + pe_header->OptionalHeader.SizeOfImage, MemoryBasicInformation, &memory_info, sizeof(memory_info), NULL); + if (NT_SUCCESS(status) && memory_info.AllocationBase == image_base) + is_valid_crc = false; + } + } +#endif +#endif + + if (data.memory_crc_info_hash() != CalcCRC(image_base + data.memory_crc_info(), data.memory_crc_info_size())) + is_valid_crc = false; + CRCValueCryptor crc_cryptor; + for (i = 0; i < data.memory_crc_info_size(); i += sizeof(CRC_INFO)) { + CRC_INFO crc_info = *reinterpret_cast<CRC_INFO *>(image_base + data.memory_crc_info() + i); + crc_info.Address = crc_cryptor.Decrypt(crc_info.Address); + crc_info.Size = crc_cryptor.Decrypt(crc_info.Size); + crc_info.Hash = crc_cryptor.Decrypt(crc_info.Hash); + + if (crc_info.Address + crc_info.Size > crc_image_size) + crc_image_size = crc_info.Address + crc_info.Size; + + if (crc_info.Hash != CalcCRC(image_base + crc_info.Address, crc_info.Size)) + is_valid_crc = false; + } + if (!is_valid_crc) { + if (data.options() & LOADER_OPTION_CHECK_PATCH) { + LoaderMessage(mtFileCorrupted); + return LOADER_ERROR; + } + tmp_loader_data->set_is_patch_detected(true); + } + } + + // calc CPU hash + int cpu_info[4]; + size_t cpu_count = 0; +#ifdef VMP_GNU +#else +#ifdef WIN_DRIVER + KAFFINITY system_mask = KeQueryActiveProcessors(); + KAFFINITY mask = 1; +#else + DWORD_PTR process_mask, system_mask; + if (GetProcessAffinityMask(process, &process_mask, &system_mask)) { + if (process_mask != system_mask) { + if (!SetProcessAffinityMask(process, system_mask)) { + LoaderMessage(mtInitializationError, CPU_HASH_ERROR); + return LOADER_ERROR; + } + } + DWORD_PTR mask = 1; +#endif + for (size_t i = 0; i < sizeof(mask) * 8; i++) { + if (system_mask & mask) { +#ifdef WIN_DRIVER + KeSetSystemAffinityThread(mask); +#else + DWORD_PTR old_mask = SetThreadAffinityMask(thread, mask); + Sleep(0); +#endif + __cpuid(cpu_info, 1); + if ((cpu_info[0] & 0xff0) == 0xfe0) + cpu_info[0] ^= 0x20; // fix Athlon bug + cpu_info[1] &= 0x00ffffff; // mask out APIC Physical ID + size_t cpu_hash = (cpu_info[0] + cpu_info[1] + cpu_salt) ^ reinterpret_cast<size_t>(tmp_loader_data); + bool cpu_found = false; + for (j = 0; j < cpu_count; j++) { + if (tmp_loader_data->cpu_hash(j) == cpu_hash) { + cpu_found = true; + break; + } + } + if (!cpu_found) { + if (cpu_count == VAR_COUNT - VAR_CPU_HASH) { + LoaderMessage(mtInitializationError, CPU_HASH_ERROR); + return LOADER_ERROR; + } + tmp_loader_data->set_cpu_hash(cpu_count++, cpu_hash); + } +#ifdef WIN_DRIVER + KeRevertToUserAffinityThread(); +#else + SetThreadAffinityMask(thread, old_mask); +#endif + } + mask <<= 1; + } +#ifndef WIN_DRIVER + if (process_mask != system_mask) + SetProcessAffinityMask(process, process_mask); + } +#endif +#endif + if (!cpu_count) { + __cpuid(cpu_info, 1); + if ((cpu_info[0] & 0xff0) == 0xfe0) + cpu_info[0] ^= 0x20; // fix Athlon bug + cpu_info[1] &= 0x00ffffff; // mask out APIC Physical ID + tmp_loader_data->set_cpu_hash(cpu_count++, (cpu_info[0] + cpu_info[1] + cpu_salt) ^ reinterpret_cast<size_t>(tmp_loader_data)); + } + tmp_loader_data->set_cpu_count(cpu_count); + + // create session key + session_key = __rdtsc(); + session_key ^= session_key >> 32; + tmp_loader_data->set_session_key(static_cast<uint32_t>(session_key)); + + // save pointer to loader_data + *(reinterpret_cast<void**>(dst_image_base + data.storage())) = tmp_loader_data; + + if (uint32_t data_runtime_entry = data.runtime_entry()) { +#ifdef VMP_GNU + typedef bool (WINAPI tRuntimeEntry)(HMODULE hModule, bool is_init); + if (reinterpret_cast<tRuntimeEntry *>(image_base + data_runtime_entry)(reinterpret_cast<HMODULE>(image_base), true) != true) + return LOADER_ERROR; +#elif defined(WIN_DRIVER) + typedef NTSTATUS (tRuntimeEntry)(HMODULE hModule, bool is_init); + if (reinterpret_cast<tRuntimeEntry *>(image_base + data_runtime_entry)(reinterpret_cast<HMODULE>(image_base), true) != STATUS_SUCCESS) + return LOADER_ERROR; +#else + typedef BOOL (WINAPI tRuntimeEntry)(HMODULE hModule, DWORD dwReason, LPVOID lpReserved); + if (reinterpret_cast<tRuntimeEntry *>(image_base + data_runtime_entry)(reinterpret_cast<HMODULE>(image_base), DLL_PROCESS_ATTACH, NULL) != TRUE) + return LOADER_ERROR; +#endif + } + + // setup delay import +#ifdef VMP_GNU +#elif defined(WIN_DRIVER) +#else + for (i = 0; i < data.delay_import_info_size(); i += sizeof(DLL_INFO)) { + DLL_INFO *dll_info = reinterpret_cast<DLL_INFO *>(image_base + data.delay_import_info() + i); + const char *dll_name = reinterpret_cast<const char *>(image_base + dll_info->Name); + HMODULE h = LoaderLoadLibraryEnc(dll_name); + + for (IMPORT_INFO *import_info = reinterpret_cast<IMPORT_INFO *>(dll_info + 1); import_info->Name != 0; import_info++, i += sizeof(IMPORT_INFO)) { + const char *api_name; + if (import_info->Name & IMAGE_ORDINAL_FLAG32) { + api_name = LPCSTR(INT_PTR(IMAGE_ORDINAL32(import_info->Name))); + } else { + api_name = LPCSTR(INT_PTR(image_base + import_info->Name)); + } + + void *p = LoaderGetProcAddress(h, api_name, true); + if (!p) { +#ifndef WIN_DRIVER + ULONG error_mode = 0; + if (tNtQueryInformationProcess *query_information_process = reinterpret_cast<tNtQueryInformationProcess *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_QUERY_INFORMATION_PROCESS_NAME), true))) { + query_information_process(process, ProcessDefaultHardErrorMode, &error_mode, sizeof(error_mode), NULL); + } + if (error_mode & SEM_FAILCRITICALERRORS) + return LOADER_ERROR; +#endif + LoaderMessage((import_info->Name & IMAGE_ORDINAL_FLAG32) ? mtOrdinalNotFound : mtProcNotFound, api_name, dll_name); + return LOADER_ERROR; + } + + *(reinterpret_cast<void **>(dst_image_base + import_info->Address)) = reinterpret_cast<uint8_t *>(p) - import_info->Key; + } + + i += sizeof(uint32_t); + } +#endif + + // reset WRITABLE flag for memory pages +#ifdef VMP_GNU + for (i = 0; i < data_section_info_size; i += sizeof(SECTION_INFO)) { + SECTION_INFO *section_info = reinterpret_cast<SECTION_INFO *>(image_base + data_section_info + i); + + int protect = section_info->Type; + if (mprotect(image_base + section_info->Address, section_info->Size, protect) != 0) { + LoaderMessage(mtInitializationError, VIRTUAL_PROTECT_ERROR); + return LOADER_ERROR; + } + } +#elif defined(WIN_DRIVER) + if (mdl) { + MmUnlockPages(mdl); + IoFreeMdl(mdl); + dst_image_base = image_base; + } +#else + if (sc_virtual_protect) { + for (i = 0; i < data_section_info_size; i += sizeof(SECTION_INFO)) { + SECTION_INFO *section_info = reinterpret_cast<SECTION_INFO *>(image_base + data_section_info + i); + + DWORD protect, old_protect; + if (section_info->Type & IMAGE_SCN_MEM_READ) + protect = (section_info->Type & IMAGE_SCN_MEM_WRITE) ? PAGE_READWRITE : PAGE_READONLY; + else + protect = PAGE_NOACCESS; + if (section_info->Type & IMAGE_SCN_MEM_EXECUTE) + protect <<= 4; // convert PAGE_XXX to PAGE_EXECUTE_XXX + void *address = image_base + section_info->Address; + SIZE_T size = section_info->Size; + if (!NT_SUCCESS(reinterpret_cast<tNtProtectVirtualMemory *>(syscall | sc_virtual_protect)(process, &address, &size, protect, &old_protect))) { + LoaderMessage(mtInitializationError, VIRTUAL_PROTECT_ERROR); + return LOADER_ERROR; + } + if (old_protect & (PAGE_NOACCESS | PAGE_GUARD)) { + if (data.options() & LOADER_OPTION_CHECK_DEBUGGER) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + tmp_loader_data->set_is_debugger_detected(true); + } + } + } else { + // check breakpoint + if (*reinterpret_cast<uint8_t*>(virtual_protect) == 0xcc) { + if (data.options() & LOADER_OPTION_CHECK_DEBUGGER) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + tmp_loader_data->set_is_debugger_detected(true); + } + + for (i = 0; i < data_section_info_size; i += sizeof(SECTION_INFO)) { + SECTION_INFO *section_info = reinterpret_cast<SECTION_INFO *>(image_base + data_section_info + i); + + DWORD protect, old_protect; + if (section_info->Type & IMAGE_SCN_MEM_READ) + protect = (section_info->Type & IMAGE_SCN_MEM_WRITE) ? PAGE_READWRITE : PAGE_READONLY; + else + protect = PAGE_NOACCESS; + if (section_info->Type & IMAGE_SCN_MEM_EXECUTE) + protect <<= 4; // convert PAGE_XXX to PAGE_EXECUTE_XXX + void *address = image_base + section_info->Address; + SIZE_T size = section_info->Size; + if (!NT_SUCCESS(virtual_protect(process, &address, &size, protect, &old_protect))) { + LoaderMessage(mtInitializationError, VIRTUAL_PROTECT_ERROR); + return LOADER_ERROR; + } + if (old_protect & (PAGE_NOACCESS | PAGE_GUARD)) { + if (data.options() & LOADER_OPTION_CHECK_DEBUGGER) { + LoaderMessage(mtDebuggerFound); + return LOADER_ERROR; + } + tmp_loader_data->set_is_debugger_detected(true); + } + } + } + tmp_loader_data->set_crc_image_size(crc_image_size); +#endif + +#ifdef __unix__ + if (data.relro_info()) { + SECTION_INFO *section_info = reinterpret_cast<SECTION_INFO *>(image_base + data.relro_info()); + + int protect = section_info->Type; + if (mprotect(image_base + section_info->Address, section_info->Size, protect) != 0) { + LoaderMessage(mtInitializationError, VIRTUAL_PROTECT_ERROR); + return LOADER_ERROR; + } + } +#endif + + // show nag + LoaderMessage(mtUnregisteredVersion); + + tmp_loader_data->set_loader_status(LOADER_SUCCESS); + return LOADER_SUCCESS; +}
\ No newline at end of file diff --git a/runtime/loader.h b/runtime/loader.h new file mode 100644 index 0000000..877629c --- /dev/null +++ b/runtime/loader.h @@ -0,0 +1,570 @@ +#ifndef LOADER_H +#define LOADER_H + +#pragma pack(push, 1) + +struct CRC_INFO { + uint32_t Address; + uint32_t Size; + uint32_t Hash; +}; + +struct FILE_CRC_INFO { + uint32_t FileSize; + // CRCInfo crc_info[1] +}; + +struct SECTION_INFO { + uint32_t Address; + uint32_t Size; + uint32_t Type; +}; + +struct PACKER_INFO { + uint32_t Src; + uint32_t Dst; +}; + +struct IAT_INFO { + uint32_t Src; + uint32_t Dst; + uint32_t Size; +}; + +struct DLL_INFO { + uint32_t Name; + // IMPORT_INFO import_info[1]; +}; + +struct IMPORT_INFO { + uint32_t Name; + uint32_t Address; + int32_t Key; +}; + +struct FIXUP_INFO { + uint32_t Address; + uint32_t BlockSize; + // uint32_t type_offset[1]; +}; + +struct RELOCATION_INFO { + uint32_t Address; + uint32_t Source; + uint32_t Type; +}; + +struct SETUP_IMAGE_DATA { + NOINLINE SETUP_IMAGE_DATA() { empty_ = 0; } + + NOINLINE uint8_t *file_base() { return reinterpret_cast<uint8_t *>(FACE_FILE_BASE) - empty_; } + NOINLINE uint8_t *image_base() { return reinterpret_cast<uint8_t *>(FACE_IMAGE_BASE) - empty_; } + NOINLINE uint32_t options() { return FACE_LOADER_OPTIONS - empty_; } + NOINLINE uint32_t storage() { return FACE_LOADER_DATA - empty_; } + NOINLINE uint32_t runtime_entry() { return FACE_RUNTIME_ENTRY - empty_; } +#ifdef __unix__ + NOINLINE uint32_t relro_info() { return FACE_GNU_RELRO_INFO - empty_; } +#elif defined(__APPLE__) +#elif defined(WIN_DRIVER) +#else + NOINLINE uint32_t tls_index_info() { return FACE_TLS_INDEX_INFO - empty_; } +#endif + + // file CRC information + NOINLINE uint32_t file_crc_info() { return FACE_FILE_CRC_INFO - empty_; } + NOINLINE uint32_t file_crc_info_size() { return FACE_FILE_CRC_INFO_SIZE - empty_; } + + // header and loader CRC information + NOINLINE uint32_t loader_crc_info() { return FACE_LOADER_CRC_INFO - empty_; } + NOINLINE uint32_t loader_crc_info_size() { return FACE_LOADER_CRC_INFO_SIZE - empty_; } + NOINLINE uint32_t loader_crc_info_hash() { return FACE_LOADER_CRC_INFO_HASH - empty_; } + + // section information + NOINLINE uint32_t section_info() { return FACE_SECTION_INFO - empty_; } + NOINLINE uint32_t section_info_size() { return FACE_SECTION_INFO_SIZE - empty_; } + + // packer information + NOINLINE uint32_t packer_info() { return FACE_PACKER_INFO - empty_; } + NOINLINE uint32_t packer_info_size() { return FACE_PACKER_INFO_SIZE - empty_; } + + // fixups information + NOINLINE uint32_t fixup_info() { return FACE_FIXUP_INFO - empty_; } + NOINLINE uint32_t fixup_info_size() { return FACE_FIXUP_INFO_SIZE - empty_; } + + // relocations information + NOINLINE uint32_t relocation_info() { return FACE_RELOCATION_INFO - empty_; } + NOINLINE uint32_t relocation_info_size() { return FACE_RELOCATION_INFO_SIZE - empty_; } + + // IAT information + NOINLINE uint32_t iat_info() { return FACE_IAT_INFO - empty_; } + NOINLINE uint32_t iat_info_size() { return FACE_IAT_INFO_SIZE - empty_; } + + // import information + NOINLINE uint32_t import_info() { return FACE_IMPORT_INFO - empty_; } + NOINLINE uint32_t import_info_size() { return FACE_IMPORT_INFO_SIZE - empty_; } + + // internal import information + NOINLINE uint32_t internal_import_info() { return FACE_INTERNAL_IMPORT_INFO - empty_; } + NOINLINE uint32_t internal_import_info_size() { return FACE_INTERNAL_IMPORT_INFO_SIZE - empty_; } + + // memory CRC information + NOINLINE uint32_t memory_crc_info() { return FACE_MEMORY_CRC_INFO - empty_; } + NOINLINE uint32_t memory_crc_info_size() { return FACE_MEMORY_CRC_INFO_SIZE - empty_; } + NOINLINE uint32_t memory_crc_info_hash() { return FACE_MEMORY_CRC_INFO_HASH - empty_; } + + // delay import information + NOINLINE uint32_t delay_import_info() { return FACE_DELAY_IMPORT_INFO - empty_; } + NOINLINE uint32_t delay_import_info_size() { return FACE_DELAY_IMPORT_INFO_SIZE - empty_; } +private: + uint32_t empty_; +}; + +#pragma pack(pop) + +#ifndef VMP_GNU + +#define MAXIMUM_FILENAME_LENGTH 256 + +typedef struct _SYSTEM_MODULE_ENTRY +{ +#ifdef _WIN64 + ULONGLONG Unknown1; + ULONGLONG Unknown2; +#else + ULONG Unknown1; + ULONG Unknown2; +#endif + PVOID BaseAddress; + ULONG Size; + ULONG Flags; + ULONG EntryIndex; + USHORT NameLength; // Length of module name not including the path, this field contains valid value only for NTOSKRNL module + USHORT PathLength; // Length of 'directory path' part of modulename + CHAR Name[MAXIMUM_FILENAME_LENGTH]; +} SYSTEM_MODULE_ENTRY; + +typedef struct _SYSTEM_MODULE_INFORMATION +{ + ULONG Count; +#ifdef _WIN64 + ULONG Unknown1; +#endif + SYSTEM_MODULE_ENTRY Module[1]; +} SYSTEM_MODULE_INFORMATION; + +typedef struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION +{ + BOOLEAN DebuggerEnabled; + BOOLEAN DebuggerNotPresent; +} SYSTEM_KERNEL_DEBUGGER_INFORMATION; + +typedef enum _MEMORY_INFORMATION_CLASS { + MemoryBasicInformation +} MEMORY_INFORMATION_CLASS, *PMEMORY_INFORMATION_CLASS; + +#ifdef WIN_DRIVER + +#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ +#define IMAGE_OS2_SIGNATURE 0x454E // NE +#define IMAGE_OS2_SIGNATURE_LE 0x454C // LE +#define IMAGE_VXD_SIGNATURE 0x454C // LE +#define IMAGE_NT_SIGNATURE 0x00004550 // PE00 + +#pragma pack(push, 2) + +typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header + WORD e_magic; // Magic number + WORD e_cblp; // Bytes on last page of file + WORD e_cp; // Pages in file + WORD e_crlc; // Relocations + WORD e_cparhdr; // Size of header in paragraphs + WORD e_minalloc; // Minimum extra paragraphs needed + WORD e_maxalloc; // Maximum extra paragraphs needed + WORD e_ss; // Initial (relative) SS value + WORD e_sp; // Initial SP value + WORD e_csum; // Checksum + WORD e_ip; // Initial IP value + WORD e_cs; // Initial (relative) CS value + WORD e_lfarlc; // File address of relocation table + WORD e_ovno; // Overlay number + WORD e_res[4]; // Reserved words + WORD e_oemid; // OEM identifier (for e_oeminfo) + WORD e_oeminfo; // OEM information; e_oemid specific + WORD e_res2[10]; // Reserved words + LONG e_lfanew; // File address of new exe header + } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; + +#pragma pack(pop) + +typedef struct _IMAGE_FILE_HEADER { + WORD Machine; + WORD NumberOfSections; + DWORD TimeDateStamp; + DWORD PointerToSymbolTable; + DWORD NumberOfSymbols; + WORD SizeOfOptionalHeader; + WORD Characteristics; +} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; + +typedef struct _IMAGE_DATA_DIRECTORY { + DWORD VirtualAddress; + DWORD Size; +} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; + +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 + +typedef struct _IMAGE_OPTIONAL_HEADER { + // + // Standard fields. + // + + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + + // + // NT additional fields. + // + + DWORD ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + DWORD SizeOfStackReserve; + DWORD SizeOfStackCommit; + DWORD SizeOfHeapReserve; + DWORD SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; + +typedef struct _IMAGE_ROM_OPTIONAL_HEADER { + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + DWORD BaseOfBss; + DWORD GprMask; + DWORD CprMask[4]; + DWORD GpValue; +} IMAGE_ROM_OPTIONAL_HEADER, *PIMAGE_ROM_OPTIONAL_HEADER; + +typedef struct _IMAGE_OPTIONAL_HEADER64 { + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + ULONGLONG ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + ULONGLONG SizeOfStackReserve; + ULONGLONG SizeOfStackCommit; + ULONGLONG SizeOfHeapReserve; + ULONGLONG SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64; + +typedef struct _IMAGE_NT_HEADERS64 { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER64 OptionalHeader; +} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64; + +typedef struct _IMAGE_NT_HEADERS { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER32 OptionalHeader; +} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; + +typedef struct _IMAGE_ROM_HEADERS { + IMAGE_FILE_HEADER FileHeader; + IMAGE_ROM_OPTIONAL_HEADER OptionalHeader; +} IMAGE_ROM_HEADERS, *PIMAGE_ROM_HEADERS; + +#ifdef _WIN64 +typedef IMAGE_NT_HEADERS64 IMAGE_NT_HEADERS; +typedef PIMAGE_NT_HEADERS64 PIMAGE_NT_HEADERS; +#else +typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS; +typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS; +#endif + +typedef struct _IMAGE_SECTION_HEADER { + BYTE Name[8]; + union { + DWORD PhysicalAddress; + DWORD VirtualSize; + } Misc; + DWORD VirtualAddress; + DWORD SizeOfRawData; + DWORD PointerToRawData; + DWORD PointerToRelocations; + DWORD PointerToLinenumbers; + WORD NumberOfRelocations; + WORD NumberOfLinenumbers; + DWORD Characteristics; +} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory +// IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage) +#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP +#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory +#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers +#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table +#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors +#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor + +#define IMAGE_REL_BASED_ABSOLUTE 0 +#define IMAGE_REL_BASED_HIGH 1 +#define IMAGE_REL_BASED_LOW 2 +#define IMAGE_REL_BASED_HIGHLOW 3 +#define IMAGE_REL_BASED_HIGHADJ 4 +#define IMAGE_REL_BASED_MIPS_JMPADDR 5 +#define IMAGE_REL_BASED_MIPS_JMPADDR16 9 +#define IMAGE_REL_BASED_IA64_IMM64 9 +#define IMAGE_REL_BASED_DIR64 10 + +#define IMAGE_ORDINAL_FLAG64 0x8000000000000000 +#define IMAGE_ORDINAL_FLAG32 0x80000000 +#define IMAGE_ORDINAL64(Ordinal) (Ordinal & 0xffff) +#define IMAGE_ORDINAL32(Ordinal) (Ordinal & 0xffff) +#define IMAGE_SNAP_BY_ORDINAL64(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG64) != 0) +#define IMAGE_SNAP_BY_ORDINAL32(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG32) != 0) + +typedef struct _IMAGE_EXPORT_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Name; + DWORD Base; + DWORD NumberOfFunctions; + DWORD NumberOfNames; + DWORD AddressOfFunctions; // RVA from base of image + DWORD AddressOfNames; // RVA from base of image + DWORD AddressOfNameOrdinals; // RVA from base of image +} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; + +#define MAX_PATH 260 + +#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 // Section contains extended relocations. +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 // Section can be discarded. +#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 // Section is not cachable. +#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 // Section is not pageable. +#define IMAGE_SCN_MEM_SHARED 0x10000000 // Section is shareable. +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable. +#define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable. +#define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writeable. + +typedef enum _SYSTEM_INFORMATION_CLASS { + SystemModuleInformation = 0xb, + SystemKernelDebuggerInformation = 0x23, + SystemFirmwareTableInformation = 0x4c +} SYSTEM_INFORMATION_CLASS; + +extern "C" { +NTKERNELAPI NTSTATUS NTAPI NtQuerySystemInformation( + SYSTEM_INFORMATION_CLASS SystemInformationClass, + PVOID SystemInformation, + ULONG SystemInformationLength, + PULONG ReturnLength); +} + +#else +#define FILE_OPEN 0x00000001 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 +#define FILE_NON_DIRECTORY_FILE 0x00000040 + +typedef enum _SECTION_INHERIT { + ViewShare=1, + ViewUnmap=2 +} SECTION_INHERIT, *PSECTION_INHERIT; + +#define SystemModuleInformation (SYSTEM_INFORMATION_CLASS)11 +#define SystemKernelDebuggerInformation (SYSTEM_INFORMATION_CLASS)35 + +#define ThreadHideFromDebugger (THREADINFOCLASS)17 + +#define ProcessDebugPort (PROCESSINFOCLASS)0x7 +#define ProcessDebugObjectHandle (PROCESSINFOCLASS)0x1e +#define ProcessDefaultHardErrorMode (PROCESSINFOCLASS)0x0c +#define ProcessInstrumentationCallback (PROCESSINFOCLASS)40 + +#define MemoryMappedFilenameInformation (MEMORY_INFORMATION_CLASS)2 + +#define STATUS_PORT_NOT_SET ((NTSTATUS)0xC0000353L) +#define STATUS_SERVICE_NOTIFICATION ((NTSTATUS)0x40000018L) +#define HARDERROR_OVERRIDE_ERRORMODE 0x10000000 + +#define NtCurrentProcess() ( (HANDLE)(LONG_PTR) -1 ) +#define NtCurrentThread() ( (HANDLE)(LONG_PTR) -2 ) + +typedef struct _PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION +{ + ULONG Version; + ULONG Reserved; + PVOID Callback; +} PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION, *PPROCESS_INSTRUMENTATION_CALLBACK_INFORMATION; + +typedef enum HardErrorResponse { + ResponseReturnToCaller, + ResponseNotHandled, + ResponseAbort, ResponseCancel, + ResponseIgnore, + ResponseNo, + ResponseOk, + ResponseRetry, + ResponseYes +} HardErrorResponse; + +typedef enum HardErrorResponseButton { + ResponseButtonOK, + ResponseButtonOKCancel, + ResponseButtonAbortRetryIgnore, + ResponseButtonYesNoCancel, + ResponseButtonYesNo, + ResponseButtonRetryCancel, + ResponseButtonCancelTryAgainContinue +} HardErrorResponseButton; + +typedef enum HardErrorResponseIcon { + IconAsterisk = 0x40, + IconError = 0x10, + IconExclamation = 0x30, + IconHand = 0x10, + IconInformation = 0x40, + IconNone = 0, + IconQuestion = 0x20, + IconStop = 0x10, + IconWarning = 0x30, + IconUserIcon = 0x80 +} HardErrorResponseIcon; + +#define SEC_IMAGE_NO_EXECUTE (SEC_IMAGE | SEC_NOCACHE) + +enum { + WINDOWS_XP = 2600, + WINDOWS_2003 = 3790, + WINDOWS_VISTA = 6000, + WINDOWS_VISTA_SP1 = 6001, + WINDOWS_VISTA_SP2 = 6002, + WINDOWS_7 = 7600, + WINDOWS_7_SP1 = 7601, + WINDOWS_8 = 9200, + WINDOWS_8_1 = 9600, + WINDOWS_10_TH1 = 10240, + WINDOWS_10_TH2 = 10586, + WINDOWS_10_RS1 = 14393, + WINDOWS_10_RS2 = 15063, + WINDOWS_10_RS3 = 16299, + WINDOWS_10_RS4 = 17134, + WINDOWS_10_RS5 = 17763, + WINDOWS_10_19H1 = 18362, + WINDOWS_10_19H2 = 18363, + WINDOWS_10_20H1 = 19041, + WINDOWS_10_20H2 = 19042, + WINDOWS_10_21H1 = 19043, + WINDOWS_10_21H2 = 19044, + WINDOWS_10_22H2 = 19045, + WINDOWS_11_21H2 = 22000, + WINDOWS_11_22H2 = 22621, +}; + +#define IS_KNOWN_WINDOWS_BUILD(b) ( \ + (b) == WINDOWS_XP || \ + (b) == WINDOWS_2003 || \ + (b) == WINDOWS_VISTA || \ + (b) == WINDOWS_VISTA_SP1 || \ + (b) == WINDOWS_VISTA_SP2 || \ + (b) == WINDOWS_7 || \ + (b) == WINDOWS_7_SP1 || \ + (b) == WINDOWS_8 || \ + (b) == WINDOWS_8_1 || \ + (b) == WINDOWS_10_TH1 || \ + (b) == WINDOWS_10_TH2 || \ + (b) == WINDOWS_10_RS1 || \ + (b) == WINDOWS_10_RS2 || \ + (b) == WINDOWS_10_RS3 || \ + (b) == WINDOWS_10_RS4 || \ + (b) == WINDOWS_10_RS5 || \ + (b) == WINDOWS_10_19H1 || \ + (b) == WINDOWS_10_19H2 || \ + (b) == WINDOWS_10_20H1 || \ + (b) == WINDOWS_10_20H2 || \ + (b) == WINDOWS_10_21H1 || \ + (b) == WINDOWS_10_21H2 || \ + (b) == WINDOWS_10_22H2 \ +) + +#endif // WIN_DRIVER + +#endif // VMP_GNU + +typedef struct _PEB32 { + BYTE Reserved1[2]; + BYTE BeingDebugged; + BYTE Reserved2[0xa1]; + ULONG OSMajorVersion; + ULONG OSMinorVersion; + USHORT OSBuildNumber; +} PEB32; + +typedef struct _PEB64 { + BYTE Reserved1[2]; + BYTE BeingDebugged; + BYTE Reserved2[0x115]; + ULONG OSMajorVersion; + ULONG OSMinorVersion; + USHORT OSBuildNumber; +} PEB64; + +#endif
\ No newline at end of file diff --git a/runtime/mac_runtime.mak b/runtime/mac_runtime.mak new file mode 100644 index 0000000..a6921d0 --- /dev/null +++ b/runtime/mac_runtime.mak @@ -0,0 +1,31 @@ +SOURCES := core.cc crypto.cc loader.cc licensing_manager.cc string_manager.cc hwid.cc objects.cc utils.cc ../third-party/lzma/LzmaDecode.cc + +PROJECT := mac_runtime +TARGET := $(PROJECT).dylib +BIN_DIR := ../bin/$(ARCH_DIR)/Release +LIB_TARGET := $(BIN_DIR)/$(PROJECT).a +TMP_DIR := ../tmp/mac/runtime/$(ARCH_DIR)/runtime +PCH_DIR := $(TMP_DIR)/runtime.gch +DEFINES := +LFLAGS := -dynamiclib +LIBS = $(SDK_LIBS) -framework DiskArbitration +DYLIBS := ../bin/libVMProtectSDK.dylib +OBJCOMP := +OBJECTS := $(addprefix $(TMP_DIR)/, $(SOURCES:.cc=.o)) + +include ../mac_common.mak + +clean: + -$(DEL_FILE) $(LIB_TARGET) + -$(DEL_FILE) $(OBJECTS) + -$(DEL_FILE) $(PCH_CPP) + -$(DEL_FILE) $(BIN_TARGET) + +$(LIB_TARGET): $(OBJECTS) $(BIN_DIR)/.sentinel + libtool $(SLIBFLAGS) -o $(LIB_TARGET) $(abspath $(OBJECTS)) $(OBJCOMP) + +$(BIN_TARGET): $(LIB_TARGET) $(OBJCOMP) $(DYLIBS) + $(LINK) $(LFLAGS) -o $(BIN_TARGET) $(OBJECTS) $(LIBS) $(OBJCOMP) $(DYLIBS) + +$(TMP_DIR)/%.o: %.cc $(PCH_CPP) $(TMP_DIR)/%/../.sentinel + $(CXX) -c -include-pch $(PCH_CPP) $(CXXFLAGS) $(INCFLAGS) -o $(abspath $@) $(abspath $<) diff --git a/runtime/mac_runtime32.mak b/runtime/mac_runtime32.mak new file mode 100644 index 0000000..7a7d548 --- /dev/null +++ b/runtime/mac_runtime32.mak @@ -0,0 +1,3 @@ +ARCH := i386 +ARCH_DIR := 32 +include mac_runtime.mak diff --git a/runtime/mac_runtime64.mak b/runtime/mac_runtime64.mak new file mode 100644 index 0000000..647be2c --- /dev/null +++ b/runtime/mac_runtime64.mak @@ -0,0 +1,3 @@ +ARCH := x86_64 +ARCH_DIR := 64 +include mac_runtime.mak diff --git a/runtime/objects.cc b/runtime/objects.cc new file mode 100644 index 0000000..374b185 --- /dev/null +++ b/runtime/objects.cc @@ -0,0 +1,59 @@ +#include "objects.h" + +#ifdef WIN_DRIVER + +extern "C" EXCEPTION_DISPOSITION __cdecl __CxxFrameHandler3(int a, int b, int c, int d) +{ + return ExceptionContinueSearch; +} + +#endif + +/** + * CriticalSection + */ + +CriticalSection::CriticalSection(CRITICAL_SECTION &critical_section) + : critical_section_(critical_section) +{ +#ifdef VMP_GNU + pthread_mutex_lock(&critical_section_); +#elif defined(WIN_DRIVER) + KeWaitForMutexObject(&critical_section_, Executive, KernelMode, FALSE, NULL); +#else + EnterCriticalSection(&critical_section_); +#endif +} + +CriticalSection::~CriticalSection() +{ +#ifdef VMP_GNU + pthread_mutex_unlock(&critical_section_); +#elif defined(WIN_DRIVER) + KeReleaseMutex(&critical_section_, FALSE); +#else + LeaveCriticalSection(&critical_section_); +#endif +} + +void CriticalSection::Init(CRITICAL_SECTION &critical_section) +{ +#ifdef VMP_GNU + pthread_mutex_init(&critical_section, NULL); +#elif defined(WIN_DRIVER) + KeInitializeMutex(&critical_section, 0); +#else + InitializeCriticalSection(&critical_section); +#endif +} + +void CriticalSection::Free(CRITICAL_SECTION &critical_section) +{ +#ifdef VMP_GNU + pthread_mutex_destroy(&critical_section); +#elif defined(WIN_DRIVER) + // do nothing +#else + DeleteCriticalSection(&critical_section); +#endif +}
\ No newline at end of file diff --git a/runtime/objects.h b/runtime/objects.h new file mode 100644 index 0000000..66f4877 --- /dev/null +++ b/runtime/objects.h @@ -0,0 +1,78 @@ +#ifndef OBJECTS_H +#define OBJECTS_H + +template<class T> +class vector +{ +public: + vector() : data_(NULL), total_(0), size_(0) {} + ~vector() { delete [] data_; } + size_t size() const { return size_; } + bool empty() const { return size_ == 0; } + const T &operator[] (size_t index) const { return data_[index]; } + T &operator[] (size_t index) {return data_[index]; } + void push_back(const T &t) + { + if (size_ == total_) { + // no free space + size_t new_total = (total_ == 0) ? 1 : total_ * 2; + T *new_data = new T[new_total]; + for (size_t i = 0; i < size_; i++) { + new_data[i] = data_[i]; + } + delete [] data_; + data_ = new_data; + total_ = new_total; + } + data_[size_++] = t; + } + void pop_back() + { + if (size_) + size_--; + } + + void erase(size_t pos) + { + if (pos >= size_) + return; // error + for (size_t i = pos; i < size_ - 1; i++) { + data_[i] = data_[i + 1]; + } + size_--; + } + + template <typename X> + size_t find(const X &v) const + { + for (size_t i = 0; i < size_; i++) { + if (data_[i] == v) + return i; + } + return -1; + } + + void clear() + { + size_ = total_ = 0; + delete [] data_; + data_ = NULL; + } +private: + T *data_; + size_t total_; + size_t size_; +}; + +class CriticalSection +{ +public: + CriticalSection(CRITICAL_SECTION &critical_section); + ~CriticalSection(); + static void Init(CRITICAL_SECTION &critical_section); + static void Free(CRITICAL_SECTION &critical_section); +private: + CRITICAL_SECTION &critical_section_; +}; + +#endif
\ No newline at end of file diff --git a/runtime/precommon.h b/runtime/precommon.h new file mode 100644 index 0000000..babb85f --- /dev/null +++ b/runtime/precommon.h @@ -0,0 +1,146 @@ +#pragma once +#ifndef PRECOMMON_PCH +#define PRECOMMON_PCH + +#define NOMINMAX +#ifdef WIN_DRIVER +#define _STL70_ +#include <ntddk.h> +#endif + +#ifdef __cplusplus +#include <string> // because of non-usual new operator +#endif + +#ifdef _DEBUG +#if defined(_MSC_VER) +#define _CRTDBG_MAP_ALLOC +#include <stdlib.h> +#include <crtdbg.h> +#ifndef DBG_NEW +#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ ) +#define new DBG_NEW +#endif +#endif +#endif + +#include <sys/stat.h> + +#if defined(__unix__) +#include <linux/limits.h> +enum { FALSE, TRUE }; +typedef void VOID; +#endif + +#if defined(_MSC_VER) +#define NOINLINE __declspec(noinline) +#define FORCE_INLINE __forceinline +#elif defined(__GNUC__) +#define NOINLINE __attribute__((noinline)) +#define FORCE_INLINE inline __attribute__((always_inline)) +#else +#define NOINLINE +#endif + +#include <stdio.h> +#include <string.h> + +#if defined(__APPLE__) || defined(__unix__) +#define VMP_GNU +#include <stdint.h> +#include <pthread.h> + +typedef int HANDLE; +typedef void *LPVOID; +typedef void *HMODULE; + +#if defined(__APPLE__) +typedef mach_port_t HPROCESS; +#endif + +#if defined(__unix__) +typedef int HPROCESS; +inline size_t strlcpy(char *dst, const char *src, size_t size) +{ + dst[size - 1] = '\0'; + strncpy(dst, src, size - 1); + return strlen(dst); +} +#endif + +#define INVALID_HANDLE_VALUE ((HANDLE)-1) +#define _countof(x) (sizeof(x) / sizeof(x[0])) +#define _strtoui64 strtoull +#define _strtoi64 strtoll +#define VMP_API +typedef char VMP_CHAR; +typedef unsigned short VMP_WCHAR; +inline void strncpy_s(char *strDestination, size_t sz, const char *strSource, size_t src_sz) { strncpy(strDestination, strSource, sz + 0 * src_sz); } +#ifdef __cplusplus +namespace os { + typedef unsigned short unicode_char; + typedef std::basic_string<unicode_char, std::char_traits<unicode_char>, std::allocator<unicode_char> > unicode_string; +}; +template <size_t sz> void strcpy_s(char (&strDestination)[sz], const char *strSource) { strlcpy(strDestination, strSource, sz); } +template <size_t sz> void strncpy_s(char (&strDestination)[sz], const char *strSource, size_t src_sz) { strncpy_s(&strDestination[0], sz, strSource, src_sz); } +#endif +#define _TRUNCATE ((size_t)-1) +#define _vsnprintf_s(dest, dest_sz, cnt, fmt, args) _vsnprintf((dest), (dest_sz), (fmt), (args)) +#define _vsnprintf vsnprintf +#define vsprintf_s vsprintf +#define sprintf_s sprintf +#define _strcmpi strcasecmp +#define _strdup strdup +#define sscanf_s sscanf +#define strcat_s strcat +#define LOWORD(l) ((uint16_t)(((uint32_t)(l)) & 0xffff)) +#define HIWORD(l) ((uint16_t)((((uint32_t)(l)) >> 16) & 0xffff)) +typedef int BOOL; +typedef unsigned int UINT; + +typedef char CHAR; +typedef uint8_t BYTE, *PBYTE; +typedef short SHORT; +typedef uint16_t WORD, USHORT, *PWORD, *PUSHORT; +typedef uint32_t DWORD, ULONG, ULONG32, *PDWORD, *PULONG, *PULONG32; +typedef int32_t LONG, LONG32, *PLONG, *PLONG32; +typedef uint64_t DWORD64, ULONGLONG, ULONG64, *PDWORD64, *PULONGLONG, *PULONG64; +typedef struct _GUID { + uint32_t Data1; + uint16_t Data2; + uint16_t Data3; + uint8_t Data4[8]; +} GUID; + +#define CRITICAL_SECTION pthread_mutex_t + +#else + +typedef signed char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef __int64 int64_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; + +#define VMP_API __stdcall +typedef wchar_t VMP_CHAR; +typedef wchar_t VMP_WCHAR; +#ifdef __cplusplus +namespace os { + typedef std::wstring unicode_string; + typedef wchar_t unicode_char; +}; +#endif + +typedef void *HPROCESS; + +#endif + +#ifdef __cplusplus +#include <algorithm> +#endif + +#endif //PRECOMMON_PCH
\ No newline at end of file diff --git a/runtime/precompiled.cc b/runtime/precompiled.cc new file mode 100644 index 0000000..5f656a4 --- /dev/null +++ b/runtime/precompiled.cc @@ -0,0 +1 @@ +#include "precompiled.h" diff --git a/runtime/precompiled.h b/runtime/precompiled.h new file mode 100644 index 0000000..939ebc0 --- /dev/null +++ b/runtime/precompiled.h @@ -0,0 +1,133 @@ +#pragma once +#ifndef WR_PCH +#define WR_PCH + +#ifndef VMP_GNU +#define WINVER 0x0500 +#define _WIN32_WINNT 0x0500 +#endif + +#include "precommon.h" + +#ifdef WIN_DRIVER +void * __cdecl operator new(size_t size); +void __cdecl operator delete(void* p); +void __cdecl operator delete(void* p, size_t); +void * __cdecl operator new[](size_t size); +void __cdecl operator delete[](void *p); +#endif + +#define RUNTIME + +#ifdef VMP_GNU +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <unistd.h> +#include <dlfcn.h> +#include <fcntl.h> +#include <ifaddrs.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/sysctl.h> +#include <sys/socket.h> +#include <sys/param.h> +#include <sys/mount.h> +#include <sys/ptrace.h> + +#ifdef __APPLE__ +#include <net/if_dl.h> +#include <net/if_types.h> +#include <sys/syslimits.h> +#include <mach/mach_init.h> +#include <mach/mach_time.h> +#include <mach/vm_map.h> +#include <mach-o/dyld.h> +#include <mach-o/fat.h> +#include <CoreFoundation/CoreFoundation.h> +#include <CoreServices/CoreServices.h> +#include <SystemConfiguration/SystemConfiguration.h> +#endif + +#define WINAPI +#ifdef __APPLE__ +#define EXPORT_API __attribute__ ((visibility ("default"))) +#else +#define EXPORT_API __attribute__ ((visibility ("protected"))) +#endif + +#else + +#define EXPORT_API __declspec(dllexport) + +#ifdef WIN_DRIVER +#include <windef.h> +#include <stdlib.h> + +#if defined(__cplusplus) +extern "C" { +#endif +void __cpuid(int a[4], int b); +void __nop(); + +#ifdef _WIN64 +unsigned __int64 __readeflags(void); +void __writeeflags(unsigned __int64); +#else +unsigned __readeflags(void); +void __writeeflags(unsigned); +#endif + +#if defined(__cplusplus) +} +#endif // WIN_DRIVER + +typedef unsigned long DWORD; +typedef int BOOL; +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef HANDLE HGLOBAL; +typedef unsigned int UINT; +#define WINAPI __stdcall +#define CRITICAL_SECTION KMUTEX + +#ifdef _WIN64 +typedef INT_PTR (FAR WINAPI *FARPROC)(); +#else +typedef int (FAR WINAPI *FARPROC)(); +#endif // _WIN64 + +#else +#include <windows.h> +#include <iphlpapi.h> +#include <intrin.h> +#include <wtsapi32.h> +#include <winternl.h> +#include <tlhelp32.h> +#endif +#endif // VMP_GNU + +#include <cassert> + +#ifndef NT_SUCCESS +#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) +#endif + +#ifndef InitializeObjectAttributes +#define InitializeObjectAttributes( p, n, a, r, s ) { \ + (p)->Length = sizeof( OBJECT_ATTRIBUTES ); \ + (p)->RootDirectory = r; \ + (p)->Attributes = a; \ + (p)->ObjectName = n; \ + (p)->SecurityDescriptor = s; \ + (p)->SecurityQualityOfService = NULL; \ + } +#endif + +#ifndef OBJ_CASE_INSENSITIVE +#define OBJ_CASE_INSENSITIVE 0x00000040L +#endif + +#endif //WR_PCH diff --git a/runtime/registry_manager.cc b/runtime/registry_manager.cc new file mode 100644 index 0000000..5e92ed2 --- /dev/null +++ b/runtime/registry_manager.cc @@ -0,0 +1,1390 @@ +#ifdef WIN_DRIVER +#else +#include "common.h" +#include "utils.h" +#include "objects.h" + +#include "crypto.h" +#include "core.h" +#include "file_manager.h" +#include "registry_manager.h" +#include "hook_manager.h" + +// should be commented out in release builds +// #define CHECKED + +#ifdef CHECKED +void XTrace0(LPCTSTR lpszText) +{ + ::OutputDebugString(lpszText); +} + +void XTrace(LPCTSTR lpszFormat, ...) +{ + va_list args; + va_start(args, lpszFormat); + int nBuf; + TCHAR szBuffer[16384]; // get rid of this hard-coded buffer + nBuf = _snwprintf_s(szBuffer, 16383, L"%p ", GetCurrentThreadId()); + nBuf += _vsnwprintf_s(szBuffer + nBuf, 16383 - nBuf, _TRUNCATE, lpszFormat, args); + ::OutputDebugString(szBuffer); + va_end(args); +} +#endif + +/** + * hooked functions + */ + +NTSTATUS WINAPI HookedNtSetValueKey(HANDLE KeyHandle, PUNICODE_STRING ValueName, ULONG TitleIndex, ULONG Type, PVOID Data, ULONG DataSize) +{ + RegistryManager *registry_manager = Core::Instance()->registry_manager(); + return registry_manager->NtSetValueKey(KeyHandle, ValueName, TitleIndex, Type, Data, DataSize); +} + +NTSTATUS WINAPI HookedNtDeleteValueKey(HANDLE KeyHandle, PUNICODE_STRING ValueName) +{ + RegistryManager *registry_manager = Core::Instance()->registry_manager(); + return registry_manager->NtDeleteValueKey(KeyHandle, ValueName); +} + +NTSTATUS WINAPI HookedNtCreateKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, ULONG TitleIndex, PUNICODE_STRING Class, ULONG CreateOptions, PULONG Disposition) +{ + RegistryManager *registry_manager = Core::Instance()->registry_manager(); + return registry_manager->NtCreateKey(KeyHandle, DesiredAccess, ObjectAttributes, TitleIndex, Class, CreateOptions, Disposition); +} + +NTSTATUS WINAPI HookedNtQueryValueKey(HANDLE KeyHandle, PUNICODE_STRING ValueName, KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, PVOID KeyValueInformation, ULONG Length, PULONG ResultLength) +{ + RegistryManager *registry_manager = Core::Instance()->registry_manager(); + return registry_manager->NtQueryValueKey(KeyHandle, ValueName, KeyValueInformationClass, KeyValueInformation, Length, ResultLength); +} + +NTSTATUS WINAPI HookedNtOpenKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) +{ + RegistryManager *registry_manager = Core::Instance()->registry_manager(); + return registry_manager->NtOpenKey(KeyHandle, DesiredAccess, ObjectAttributes); +} + +NTSTATUS WINAPI HookedNtOpenKeyEx(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, ULONG OpenOptions) +{ + RegistryManager *registry_manager = Core::Instance()->registry_manager(); + return registry_manager->NtOpenKeyEx(KeyHandle, DesiredAccess, ObjectAttributes, OpenOptions); +} + +NTSTATUS WINAPI HookedNtDeleteKey(HANDLE KeyHandle) +{ + RegistryManager *registry_manager = Core::Instance()->registry_manager(); + return registry_manager->NtDeleteKey(KeyHandle); +} + +NTSTATUS WINAPI HookedNtQueryKey(HANDLE KeyHandle, KEY_INFORMATION_CLASS KeyInformationClass, PVOID KeyInformation, ULONG Length, PULONG ResultLength) +{ + RegistryManager *registry_manager = Core::Instance()->registry_manager(); + return registry_manager->NtQueryKey(KeyHandle, KeyInformationClass, KeyInformation, Length, ResultLength); +} + +NTSTATUS WINAPI HookedNtEnumerateValueKey(HANDLE KeyHandle, ULONG Index, KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, PVOID KeyValueInformation, ULONG Length, PULONG ResultLength) +{ + RegistryManager *registry_manager = Core::Instance()->registry_manager(); + return registry_manager->NtEnumerateValueKey(KeyHandle, Index, KeyValueInformationClass, KeyValueInformation, Length, ResultLength); +} + +NTSTATUS WINAPI HookedNtEnumerateKey(HANDLE KeyHandle, ULONG Index, KEY_INFORMATION_CLASS KeyInformationClass, PVOID KeyInformation, ULONG Length, PULONG ResultLength) +{ + RegistryManager *registry_manager = Core::Instance()->registry_manager(); + return registry_manager->NtEnumerateKey(KeyHandle, Index, KeyInformationClass, KeyInformation, Length, ResultLength); +} + +/** + * RegistryValue + */ + +RegistryValue::RegistryValue(const wchar_t *name) + : name_(NULL), type_(REG_NONE), data_(NULL), size_(0) +{ + size_t size = wcslen(name) + 1; + name_ = new wchar_t[size]; + memcpy(name_, name, size * sizeof(wchar_t)); +} + +RegistryValue::~RegistryValue() +{ + delete [] name_; + delete [] data_; +} + +void RegistryValue::SetValue(uint32_t type, void *data, uint32_t size) +{ + type_ = type; + size_ = size; + delete [] data_; + if (size) { + data_ = new uint8_t[size_]; + memcpy(data_, data, size_); + } else { + data_ = NULL; + } +} + +/** + * RegistryKey + */ + +RegistryKey::RegistryKey() + : name_(NULL), owner_(NULL), is_real_(false), is_wow_(false), last_write_time_(0) +{ + +} + +RegistryKey::RegistryKey(RegistryKey *owner, const wchar_t *name, bool is_real) + : name_(NULL), owner_(owner), is_real_(is_real), is_wow_(false), last_write_time_(0) +{ + size_t size = wcslen(name) + 1; + name_ = new wchar_t[size]; + memcpy(name_, name, size * sizeof(wchar_t)); +} + +RegistryKey::~RegistryKey() +{ + for (size_t i = 0; i < values_.size(); i++) { + RegistryValue *value = values_[i]; + delete value; + } + values_.clear(); + + for (size_t i = 0; i < keys_.size(); i++) { + RegistryKey *key = keys_[i]; + delete key; + } + keys_.clear(); + + delete [] name_; +} + +RegistryValue *RegistryKey::GetValue(const wchar_t *value_name) const +{ + if (!value_name) + value_name = L""; + for (size_t i = 0; i < values_.size(); i++) { + RegistryValue *value = values_[i]; + if (_wcsicmp(value_name, value->name()) == 0) + return value; + } + return NULL; +} + +RegistryValue *RegistryKey::AddValue(wchar_t *value_name) +{ + if (!value_name) + value_name = L""; + RegistryValue *value = new RegistryValue(value_name); + values_.push_back(value); + return value; +} + +void RegistryKey::SetValue(wchar_t *value_name, uint32_t type, void *data, uint32_t size) +{ + RegistryValue *value = GetValue(value_name); + if (!value) + value = AddValue(value_name); + value->SetValue(type, data, size); + + FILETIME system_time; + GetSystemTimeAsFileTime(&system_time); + last_write_time_ = static_cast<uint64_t>(system_time.dwHighDateTime) << 32 | static_cast<uint64_t>(system_time.dwLowDateTime); +} + +bool RegistryKey::DeleteValue(wchar_t *value_name) +{ + if (!value_name) + value_name = L""; + for (size_t i = 0; i < values_.size(); i++) { + RegistryValue *value = values_[i]; + if (_wcsicmp(value_name, value->name()) == 0) { + delete value; + values_.erase(i); + return true; + } + } + return false; +} + +bool RegistryKey::is_wow_node(const wchar_t *name) const +{ + bool ret = (is_wow_ && _wcsicmp(L"Wow6432Node", name) == 0); +#ifdef CHECKED + XTrace(L"is_wow_node: %s = %d\n", name, ret ? 1 : 0); +#endif + return ret; +} + +RegistryKey *RegistryKey::GetChild(const wchar_t *name) const +{ + if (!name || *name == 0) + return NULL; + + if (is_wow_node(name)) + return const_cast<RegistryKey *>(this); + + for (size_t i = 0; i < keys_.size(); i++) { + RegistryKey *key = keys_[i]; + if (_wcsicmp(name, key->name()) == 0) + return key; + } + return NULL; +} + +RegistryKey *RegistryKey::GetKey(const wchar_t *name) const +{ + if (!name || *name == 0) + return NULL; + + if (*name == L'\\') + name++; + const wchar_t *sub_name = wcschr(name, L'\\'); + if (!sub_name) + return GetChild(name); + + RegistryKey *key = GetChild(UnicodeString(name, sub_name - name).c_str()); + return key ? key->GetKey(sub_name) : NULL; +} + +RegistryKey *RegistryKey::AddChild(const wchar_t *name, bool is_real, bool *is_exists) +{ + if (!name || *name == 0) + return NULL; + + RegistryKey *key = is_wow_node(name) ? this : GetChild(name); + if (is_exists) + *is_exists = (key != NULL); + if (!key) { + key = new RegistryKey(this, name, is_real); + keys_.push_back(key); + } + return key; +} + +RegistryKey *RegistryKey::AddKey(const wchar_t *name, bool is_real, bool *is_exists) +{ + if (!name || *name == 0) + return NULL; + + if (*name == L'\\') + name++; + const wchar_t *sub_name = wcschr(name, L'\\'); + if (!sub_name) + return AddChild(name, is_real, is_exists); + + RegistryKey *key = AddChild(UnicodeString(name, sub_name - name).c_str(), is_real, is_exists); + return key ? key->AddKey(sub_name, is_real, is_exists) : NULL; +} + +bool RegistryKey::DeleteKey(RegistryKey *key) +{ + size_t index = keys_.find(key); + if (index != -1) { + keys_.erase(index); + delete key; + return true; + } + return false; +} + +UnicodeString RegistryKey::full_name() const +{ + if (!owner_) + return UnicodeString(); + return owner_->full_name() + L'\\' + name_; +} + +/** + * RegistryManager + */ + +RegistryManager::RegistryManager(const uint8_t *data, HMODULE instance, const uint8_t *key, VirtualObjectList *objects) + : instance_(instance) + , data_(data) + , objects_(objects) + , nt_set_value_key_(NULL) + , nt_delete_value_key_(NULL) + , nt_create_key_(NULL) + , nt_open_key_(NULL) + , nt_open_key_ex_(NULL) + , nt_query_value_key_(NULL) + , nt_delete_key_(NULL) + , nt_query_key_(NULL) + , nt_enumerate_value_key_(NULL) + , nt_enumerate_key_(NULL) + , append_mode_(false) +{ + key_ = *(reinterpret_cast<const uint32_t *>(key)); + +//#ifndef _WIN64 + static const wchar_t *wow_keys[] = { + L"\\REGISTRY\\MACHINE\\SOFTWARE\\Classes" + }; + + for (size_t i = 0; i < _countof(wow_keys); i++) { + RegistryKey *key = cache_.AddKey(wow_keys[i], true, NULL); + if (key) + key->set_is_wow(true); + } +//#endif +} + +void RegistryManager::HookAPIs(HookManager &hook_manager) +{ + hook_manager.Begin(); + HMODULE dll = GetModuleHandleA(VMProtectDecryptStringA("ntdll.dll")); + nt_set_value_key_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtSetValueKey"), &HookedNtSetValueKey); + nt_delete_value_key_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtDeleteValueKey"), &HookedNtDeleteValueKey); + nt_create_key_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtCreateKey"), &HookedNtCreateKey); + nt_open_key_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtOpenKey"), &HookedNtOpenKey); + nt_open_key_ex_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtOpenKeyEx"), &HookedNtOpenKeyEx, false); + nt_query_value_key_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtQueryValueKey"), &HookedNtQueryValueKey); + nt_delete_key_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtDeleteKey"), &HookedNtDeleteKey); + nt_query_key_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtQueryKey"), &HookedNtQueryKey); + nt_enumerate_value_key_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtEnumerateValueKey"), &HookedNtEnumerateValueKey); + nt_enumerate_key_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtEnumerateKey"), &HookedNtEnumerateKey); + hook_manager.End(); +} + +void RegistryManager::UnhookAPIs(HookManager &hook_manager) +{ + hook_manager.Begin(); + hook_manager.UnhookAPI(nt_set_value_key_); + hook_manager.UnhookAPI(nt_delete_value_key_); + hook_manager.UnhookAPI(nt_create_key_); + hook_manager.UnhookAPI(nt_open_key_); + hook_manager.UnhookAPI(nt_open_key_ex_); + hook_manager.UnhookAPI(nt_query_value_key_); + hook_manager.UnhookAPI(nt_delete_key_); + hook_manager.UnhookAPI(nt_query_key_); + hook_manager.UnhookAPI(nt_enumerate_value_key_); + hook_manager.UnhookAPI(nt_enumerate_key_); + hook_manager.End(); +} + +REGISTRY_DIRECTORY RegistryManager::DecryptDirectory(const REGISTRY_DIRECTORY *directory_enc) const +{ + REGISTRY_DIRECTORY res; + res.Reserved1 = directory_enc->Reserved1 ^ key_; + res.Reserved2 = directory_enc->Reserved2 ^ key_; + return res; +} + +void RegistryManager::BeginRegisterServer() +{ + append_mode_ = true; +} + +void RegistryManager::EndRegisterServer() +{ + append_mode_ = false; +} + +NTSTATUS __forceinline RegistryManager::TrueNtSetValueKey(HANDLE KeyHandle, PUNICODE_STRING ValueName, ULONG TitleIndex, ULONG Type, PVOID Data, ULONG DataSize) +{ + typedef NTSTATUS (WINAPI tNtSetValueKey)(HANDLE KeyHandle, PUNICODE_STRING ValueName, ULONG TitleIndex, ULONG Type, PVOID Data, ULONG DataSize); + return reinterpret_cast<tNtSetValueKey *>(nt_set_value_key_)(KeyHandle, ValueName, TitleIndex, Type, Data, DataSize); +} + +NTSTATUS __forceinline RegistryManager::TrueNtDeleteValueKey(HANDLE KeyHandle, PUNICODE_STRING ValueName) +{ + typedef NTSTATUS (WINAPI tNtDeleteValueKey)(HANDLE KeyHandle, PUNICODE_STRING ValueName); + return reinterpret_cast<tNtDeleteValueKey *>(nt_delete_value_key_)(KeyHandle, ValueName); +} + +NTSTATUS __forceinline RegistryManager::TrueNtCreateKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, ULONG TitleIndex, PUNICODE_STRING Class, ULONG CreateOptions, PULONG Disposition) +{ + typedef NTSTATUS (WINAPI tNtCreateKey)(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, ULONG TitleIndex, PUNICODE_STRING Class, ULONG CreateOptions, PULONG Disposition); + return reinterpret_cast<tNtCreateKey *>(nt_create_key_)(KeyHandle, DesiredAccess, ObjectAttributes, TitleIndex, Class, CreateOptions, Disposition); +} + +NTSTATUS __forceinline RegistryManager::TrueNtQueryValueKey(HANDLE KeyHandle, PUNICODE_STRING ValueName, KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, PVOID KeyValueInformation, ULONG Length, PULONG ResultLength) +{ + typedef NTSTATUS (WINAPI tNtQueryValueKey)(HANDLE KeyHandle, PUNICODE_STRING ValueName, KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, PVOID KeyValueInformation, ULONG Length, PULONG ResultLength); + return reinterpret_cast<tNtQueryValueKey *>(nt_query_value_key_)(KeyHandle, ValueName, KeyValueInformationClass, KeyValueInformation, Length, ResultLength); +} + +NTSTATUS __forceinline RegistryManager::TrueNtOpenKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) +{ + typedef NTSTATUS (WINAPI tNtOpenKey)(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes); + return reinterpret_cast<tNtOpenKey *>(nt_open_key_)(KeyHandle, DesiredAccess, ObjectAttributes); +} + +NTSTATUS __forceinline RegistryManager::TrueNtOpenKeyEx(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, ULONG OpenOptions) +{ + typedef NTSTATUS (WINAPI tNtOpenKeyEx)(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, ULONG OpenOptions); + return reinterpret_cast<tNtOpenKeyEx *>(nt_open_key_ex_)(KeyHandle, DesiredAccess, ObjectAttributes, OpenOptions); +} + +NTSTATUS __forceinline RegistryManager::TrueNtDeleteKey(HANDLE KeyHandle) +{ + typedef NTSTATUS (WINAPI tNtDeleteKey)(HANDLE KeyHandle); + return reinterpret_cast<tNtDeleteKey *>(nt_delete_key_)(KeyHandle); +} + +NTSTATUS __forceinline RegistryManager::TrueNtQueryKey(HANDLE KeyHandle, KEY_INFORMATION_CLASS KeyInformationClass, PVOID KeyInformation, ULONG Length, PULONG ResultLength) +{ + typedef NTSTATUS (WINAPI tNtQueryKey)(HANDLE KeyHandle, KEY_INFORMATION_CLASS KeyInformationClass, PVOID KeyInformation, ULONG Length, PULONG ResultLength); + return reinterpret_cast<tNtQueryKey *>(nt_query_key_)(KeyHandle, KeyInformationClass, KeyInformation, Length, ResultLength); +} + +NTSTATUS __forceinline RegistryManager::TrueNtEnumerateValueKey(HANDLE KeyHandle, ULONG Index, KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, PVOID KeyValueInformation, ULONG Length, PULONG ResultLength) +{ + typedef NTSTATUS (WINAPI tNtEnumerateValueKey)(HANDLE KeyHandle, ULONG Index, KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, PVOID KeyValueInformation, ULONG Length, PULONG ResultLength); + return reinterpret_cast<tNtEnumerateValueKey *>(nt_enumerate_value_key_)(KeyHandle, Index, KeyValueInformationClass, KeyValueInformation, Length, ResultLength); +} + +NTSTATUS __forceinline RegistryManager::TrueNtEnumerateKey(HANDLE KeyHandle, ULONG Index, KEY_INFORMATION_CLASS KeyInformationClass, PVOID KeyInformation, ULONG Length, PULONG ResultLength) +{ + typedef NTSTATUS (WINAPI tNtEnumerateKey)(HANDLE KeyHandle, ULONG Index, KEY_INFORMATION_CLASS KeyInformationClass, PVOID KeyInformation, ULONG Length, PULONG ResultLength); + return reinterpret_cast<tNtEnumerateKey *>(nt_enumerate_key_)(KeyHandle, Index, KeyInformationClass, KeyInformation, Length, ResultLength); +} + +NTSTATUS __forceinline RegistryManager::TrueNtQueryObject(HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength) +{ + return Core::Instance()->TrueNtQueryObject(Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength, ReturnLength); +} + +NTSTATUS RegistryManager::NtSetValueKey(HANDLE KeyHandle, PUNICODE_STRING ValueName, ULONG TitleIndex, ULONG Type, PVOID Data, ULONG DataSize) +{ +#ifdef CHECKED + UnicodeString s(ValueName->Buffer, ValueName->Length / sizeof(wchar_t)); + XTrace(L"->NtSetValueKey %p %s\n", KeyHandle, s.c_str()); +#endif + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetKey(KeyHandle); + if (object && object->ref()) { + if ((object->access() & KEY_SET_VALUE) == 0) + { +#ifdef CHECKED + XTrace(L"NtSetValueKey STATUS_ACCESS_DENIED\n"); +#endif + return STATUS_ACCESS_DENIED; + } + + RegistryKey *key = static_cast<RegistryKey *>(object->ref()); + try { + key->SetValue(ValueName->Buffer, Type, Data, DataSize); +#ifdef CHECKED + XTrace(L"NtSetValueKey STATUS_SUCCESS\n"); +#endif + return STATUS_SUCCESS; + } catch(...) { +#ifdef CHECKED + XTrace(L"NtSetValueKey STATUS_ACCESS_VIOLATION\n"); +#endif + return STATUS_ACCESS_VIOLATION; + } + } + } + + NTSTATUS ret = TrueNtSetValueKey(KeyHandle, ValueName, TitleIndex, Type, Data, DataSize); +#ifdef CHECKED + XTrace(L"TrueNtSetValueKey %p\n", ret); +#endif + return ret; +} + +NTSTATUS RegistryManager::NtDeleteValueKey(HANDLE KeyHandle, PUNICODE_STRING ValueName) +{ +#ifdef CHECKED + UnicodeString s(ValueName->Buffer, ValueName->Length / sizeof(wchar_t)); + XTrace(L"->NtDeleteValueKey %p %s\n", KeyHandle, s.c_str()); +#endif + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetKey(KeyHandle); + if (object && object->ref()) { + if ((object->access() & KEY_SET_VALUE) == 0) + { +#ifdef CHECKED + XTrace(L"NtDeleteValueKey STATUS_ACCESS_DENIED\n"); +#endif + return STATUS_ACCESS_DENIED; + } + + RegistryKey *key = static_cast<RegistryKey *>(object->ref()); + try { + NTSTATUS ret = key->DeleteValue(ValueName->Buffer) ? STATUS_SUCCESS : STATUS_OBJECT_NAME_NOT_FOUND; +#ifdef CHECKED + XTrace(L"NtDeleteValueKey STATUS_SUCCESS\n"); +#endif + return ret; + } catch(...) { +#ifdef CHECKED + XTrace(L"NtSetValueKey STATUS_ACCESS_VIOLATION\n"); +#endif + return STATUS_ACCESS_VIOLATION; + } + } + } + + NTSTATUS ret = TrueNtDeleteValueKey(KeyHandle, ValueName); +#ifdef CHECKED + XTrace(L"TrueNtDeleteValueKey %p\n", ret); +#endif + return ret; +} + +RegistryKey *RegistryManager::GetRootKey(HANDLE root, uint32_t *access, bool can_create) +{ + RegistryKey *res = NULL; + if (root) { + VirtualObject *object = objects_->GetKey(root); + if (object && object->ref()) { + // root is a virtual key + res = static_cast<RegistryKey *>(object->ref()); + if (access) + *access = object->access(); + } else { + // root is a real key + KEY_NAME_INFORMATION info; + DWORD size; + if (TrueNtQueryKey(root, KeyNameInformation, &info, sizeof(info), &size) == STATUS_BUFFER_OVERFLOW) { + KEY_NAME_INFORMATION *data = reinterpret_cast<KEY_NAME_INFORMATION *>(new uint8_t[size]); + if (NT_SUCCESS(TrueNtQueryKey(root, KeyNameInformation, data, size, &size))) { + UnicodeString str(data->Name, data->NameLength / sizeof(wchar_t)); + res = can_create ? cache_.AddKey(str.c_str(), true, NULL) : cache_.GetKey(str.c_str()); + if (access) { + if (object) + *access = object->access(); + else { + PUBLIC_OBJECT_BASIC_INFORMATION info; + *access = (NT_SUCCESS(TrueNtQueryObject(root, ObjectBasicInformation, &info, sizeof(info), NULL))) ? info.GrantedAccess : 0; + } + } + } + delete [] data; + } + } + } else { + res = &cache_; + if (access) + *access = KEY_CREATE_SUB_KEY; + } + return res; +} + +NTSTATUS RegistryManager::NtCreateKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, ULONG TitleIndex, PUNICODE_STRING Class, ULONG CreateOptions, PULONG Disposition) +{ +#ifdef CHECKED + UnicodeString s(ObjectAttributes->ObjectName->Buffer, ObjectAttributes->ObjectName->Length / sizeof(wchar_t)); + XTrace(L"->NtCreateKey %p %s DesiredAccess=%p\n", ObjectAttributes->RootDirectory, s.c_str(), DesiredAccess); +#endif + { + CriticalSection cs(objects_->critical_section()); + + try { + uint32_t root_access = 0; + RegistryKey *root_key = GetRootKey(ObjectAttributes->RootDirectory, &root_access, append_mode_); + if (root_key) { + bool is_exists = true; + RegistryKey *key; + if (ObjectAttributes->ObjectName->Buffer) { + UnicodeString str(ObjectAttributes->ObjectName->Buffer, ObjectAttributes->ObjectName->Length / sizeof(wchar_t)); + key = ((root_access & KEY_CREATE_SUB_KEY) != 0 && (append_mode_ || !root_key->is_real())) ? root_key->AddKey(str.c_str(), false, &is_exists) : root_key->GetKey(str.c_str()); + } else { + key = root_key; + } + if (key) { + if (!key->is_real()) { + HANDLE newHandle = ::CreateEventA(NULL, false, false, NULL); +#ifdef CHECKED + if(objects_->GetKey(newHandle)) + { + XTrace(L"NtCreateKey HANDLE REUSE DETECTED\n"); + } +#endif + VirtualObject *object = objects_->Add(OBJECT_KEY, key, newHandle, DesiredAccess); + *KeyHandle = object->handle(); + if (Disposition) + *Disposition = is_exists ? REG_OPENED_EXISTING_KEY : REG_CREATED_NEW_KEY; +#ifdef CHECKED + XTrace(L"NtCreateKey STATUS_SUCCESS, is_exists=%d, h=%p\n", is_exists?1:0, *KeyHandle); +#endif + return STATUS_SUCCESS; + } + } else if (ObjectAttributes->RootDirectory) { + VirtualObject *object = objects_->GetKey(ObjectAttributes->RootDirectory); + if (object && object->ref()) + { + NTSTATUS ret = ((root_access & KEY_CREATE_SUB_KEY) == 0) ? STATUS_ACCESS_DENIED : STATUS_INVALID_PARAMETER; +#ifdef CHECKED + XTrace(L"NtCreateKey re=%d\n", ret); +#endif + return ret; + } + } + } + } catch(...) { +#ifdef CHECKED + XTrace(L"NtCreateKey STATUS_ACCESS_VIOLATION\n"); +#endif + return STATUS_ACCESS_VIOLATION; + } + } + + NTSTATUS ret = TrueNtCreateKey(KeyHandle, DesiredAccess, ObjectAttributes, TitleIndex, Class, CreateOptions, Disposition); +#ifdef CHECKED + XTrace(L"TrueNtCreateKey %p h=%p\n", ret, *KeyHandle); +#endif + return ret; +} + +NTSTATUS RegistryManager::NtOpenKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) +{ +#ifdef CHECKED + UnicodeString s(ObjectAttributes->ObjectName->Buffer, ObjectAttributes->ObjectName->Length / sizeof(wchar_t)); + XTrace(L"->NtOpenKey %p %s DesiredAccess=%p\n", ObjectAttributes->RootDirectory, s.c_str(), DesiredAccess); +#endif + { + CriticalSection cs(objects_->critical_section()); + + try { + RegistryKey *root_key = GetRootKey(ObjectAttributes->RootDirectory, NULL, false); + if (root_key) { + RegistryKey *key = ObjectAttributes->ObjectName->Buffer ? root_key->GetKey(UnicodeString(ObjectAttributes->ObjectName->Buffer, ObjectAttributes->ObjectName->Length / sizeof(wchar_t)).c_str()) : root_key; + if (key) { + if (!key->is_real()) { + HANDLE newHandle = ::CreateEventA(NULL, false, false, NULL); +#ifdef CHECKED + if(objects_->GetKey(newHandle)) + { + XTrace(L"NtOpenKey HANDLE REUSE DETECTED\n"); + } +#endif + VirtualObject *object = objects_->Add(OBJECT_KEY, key, newHandle, DesiredAccess); + *KeyHandle = object->handle(); +#ifdef CHECKED + XTrace(L"NtOpenKey STATUS_SUCCESS, h=%p\n", *KeyHandle); +#endif + return STATUS_SUCCESS; + } + } else if (ObjectAttributes->RootDirectory) { + VirtualObject *object = objects_->GetKey(ObjectAttributes->RootDirectory); + if (object && object->ref()) + { +#ifdef CHECKED + XTrace(L"NtOpenKey STATUS_OBJECT_NAME_NOT_FOUND\n"); +#endif + return STATUS_OBJECT_NAME_NOT_FOUND; + } + } + } + } catch(...) { +#ifdef CHECKED + XTrace(L"NtOpenKey STATUS_ACCESS_VIOLATION\n"); +#endif + return STATUS_ACCESS_VIOLATION; + } + + if (append_mode_ && (DesiredAccess & (MAXIMUM_ALLOWED | KEY_SET_VALUE | KEY_CREATE_SUB_KEY))) { + NTSTATUS status = TrueNtOpenKey(KeyHandle, KEY_READ | (DesiredAccess & KEY_WOW64_RES), ObjectAttributes); +#ifdef CHECKED + XTrace(L"TrueNtOpenKey for MAXIMUM_ALLOWED %p h=%p\n", status, *KeyHandle); +#endif + if (NT_SUCCESS(status)) { + RegistryKey *root_key = GetRootKey(ObjectAttributes->RootDirectory, NULL, true); + if (root_key) { + bool is_exists = true; + RegistryKey *key = ObjectAttributes->ObjectName->Buffer ? root_key->AddKey(UnicodeString(ObjectAttributes->ObjectName->Buffer, ObjectAttributes->ObjectName->Length / sizeof(wchar_t)).c_str(), false, &is_exists) : root_key; + if (key) + objects_->Add(OBJECT_KEY, key, *KeyHandle, DesiredAccess); + } + } + return status; + } + } + + NTSTATUS ret = TrueNtOpenKey(KeyHandle, DesiredAccess, ObjectAttributes); +#ifdef CHECKED + XTrace(L"TrueNtOpenKey %p h=%p\n", ret, *KeyHandle); +#endif + return ret; +} + +NTSTATUS RegistryManager::NtOpenKeyEx(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, ULONG OpenOptions) +{ +#ifdef CHECKED + UnicodeString s(ObjectAttributes->ObjectName->Buffer, ObjectAttributes->ObjectName->Length / sizeof(wchar_t)); + XTrace(L"->NtOpenKeyEx %p %s DesiredAccess=%p\n", ObjectAttributes->RootDirectory, s.c_str(), DesiredAccess); +#endif + { + CriticalSection cs(objects_->critical_section()); + + try { + RegistryKey *root_key = GetRootKey(ObjectAttributes->RootDirectory, NULL, false); + if (root_key) { + RegistryKey *key = ObjectAttributes->ObjectName->Buffer ? root_key->GetKey(UnicodeString(ObjectAttributes->ObjectName->Buffer, ObjectAttributes->ObjectName->Length / sizeof(wchar_t)).c_str()) : root_key; + if (key) { + if (!key->is_real()) { + VirtualObject *object = objects_->Add(OBJECT_KEY, key, ::CreateEventA(NULL, false, false, NULL), DesiredAccess); + *KeyHandle = object->handle(); +#ifdef CHECKED + XTrace(L"NtOpenKeyEx STATUS_SUCCESS, h=%p\n", *KeyHandle); +#endif + return STATUS_SUCCESS; + } + } else if (ObjectAttributes->RootDirectory) { + VirtualObject *object = objects_->GetKey(ObjectAttributes->RootDirectory); + if (object && object->ref()) + { +#ifdef CHECKED + XTrace(L"NtOpenKeyEx STATUS_OBJECT_NAME_NOT_FOUND\n"); +#endif + return STATUS_OBJECT_NAME_NOT_FOUND; + } + } + } + } catch(...) { +#ifdef CHECKED + XTrace(L"NtOpenKeyEx STATUS_ACCESS_VIOLATION\n"); +#endif + return STATUS_ACCESS_VIOLATION; + } + + if (append_mode_ && (DesiredAccess & (MAXIMUM_ALLOWED | KEY_SET_VALUE | KEY_CREATE_SUB_KEY))) { + NTSTATUS status = TrueNtOpenKey(KeyHandle, KEY_READ | (DesiredAccess & KEY_WOW64_RES), ObjectAttributes); +#ifdef CHECKED + XTrace(L"TrueNtOpenKey for MAXIMUM_ALLOWED %p h=%p\n", status, *KeyHandle); +#endif + if (NT_SUCCESS(status)) { + RegistryKey *root_key = GetRootKey(ObjectAttributes->RootDirectory, NULL, true); + if (root_key) { + bool is_exists = true; + RegistryKey *key = ObjectAttributes->ObjectName->Buffer ? root_key->AddKey(UnicodeString(ObjectAttributes->ObjectName->Buffer, ObjectAttributes->ObjectName->Length / sizeof(wchar_t)).c_str(), false, &is_exists) : root_key; + if (key) + objects_->Add(OBJECT_KEY, key, *KeyHandle, DesiredAccess); + } + } + return status; + } + } + + NTSTATUS ret = TrueNtOpenKeyEx(KeyHandle, DesiredAccess, ObjectAttributes, OpenOptions); +#ifdef CHECKED + XTrace(L"TrueNtOpenKeyEx %p h=%p\n", ret, *KeyHandle); +#endif + return ret; +} + +NTSTATUS RegistryManager::QueryValueKey(RegistryValue *value, KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, PVOID KeyValueInformation, ULONG Length, PULONG ResultLength) +{ + if (!value) + { +#ifdef CHECKED + XTrace(L"QueryValueKey STATUS_INVALID_PARAMETER\n"); +#endif + return STATUS_INVALID_PARAMETER; + } + + switch (KeyValueInformationClass) { + case KeyValueBasicInformation: + { + uint32_t name_size = static_cast<ULONG>(wcslen(value->name()) * sizeof(wchar_t)); + uint32_t min_size = offsetof(KEY_VALUE_BASIC_INFORMATION, Name); + uint32_t result_size = min_size + name_size; + if (ResultLength) + *ResultLength = result_size; + if (Length < min_size) + return STATUS_BUFFER_TOO_SMALL; + + KEY_VALUE_BASIC_INFORMATION *info = static_cast<KEY_VALUE_BASIC_INFORMATION *>(KeyValueInformation); + info->TitleIndex = 0; + info->Type = value->type(); + info->NameLength = name_size; + + if (Length < result_size) + return STATUS_BUFFER_OVERFLOW; + + memcpy(info->Name, value->name(), name_size); + } + return STATUS_SUCCESS; + + case KeyValueFullInformation: + case KeyValueFullInformationAlign64: + { + uint32_t align = 0; + if (KeyValueInformationClass == KeyValueFullInformationAlign64) { + align = 8 - ULONG(INT_PTR(KeyValueInformation)) % 8; //-V221 + KeyValueInformation = static_cast<uint8_t *>(KeyValueInformation) + align; + } + uint32_t name_size = static_cast<ULONG>(wcslen(value->name()) * sizeof(wchar_t)); + uint32_t data_size = value->size(); + uint32_t min_size = offsetof(KEY_VALUE_FULL_INFORMATION, Name) + align; + uint32_t result_size = min_size + name_size + data_size; + if (ResultLength) + *ResultLength = result_size; + if (Length < min_size) + return STATUS_BUFFER_TOO_SMALL; + + KEY_VALUE_FULL_INFORMATION *info = static_cast<KEY_VALUE_FULL_INFORMATION *>(KeyValueInformation); + info->TitleIndex = 0; + info->Type = value->type(); + info->NameLength = name_size; + info->DataLength = data_size; + info->DataOffset = min_size + name_size; + + if (Length < result_size) + return STATUS_BUFFER_OVERFLOW; + + memcpy(info->Name, value->name(), name_size); + memcpy(reinterpret_cast<uint8_t*>(info) + info->DataOffset, value->data(), data_size); + } + return STATUS_SUCCESS; + + case KeyValuePartialInformation: + case KeyValuePartialInformationAlign64: + { + uint32_t align = 0; + if (KeyValueInformationClass == KeyValuePartialInformationAlign64) { + align = 8 - ULONG(INT_PTR(KeyValueInformation)) % 8; //-V221 + KeyValueInformation = static_cast<uint8_t *>(KeyValueInformation) + align; + } + uint32_t data_size = value->size(); + uint32_t min_size = offsetof(KEY_VALUE_PARTIAL_INFORMATION, Data) + align; + uint32_t result_size = min_size + data_size; + if (ResultLength) + *ResultLength = result_size; + if (Length < min_size) + { +#ifdef CHECKED + XTrace(L"QueryValueKey STATUS_BUFFER_TOO_SMALL\n"); +#endif + return STATUS_BUFFER_TOO_SMALL; + } + + KEY_VALUE_PARTIAL_INFORMATION *info = static_cast<KEY_VALUE_PARTIAL_INFORMATION *>(KeyValueInformation); + info->TitleIndex = 0; + info->Type = value->type(); + info->DataLength = data_size; + + if (Length < result_size) + { +#ifdef CHECKED + XTrace(L"QueryValueKey STATUS_BUFFER_OVERFLOW\n"); +#endif + return STATUS_BUFFER_OVERFLOW; + } + +#ifdef CHECKED + XTrace(L"QueryValueKey %s %d\n", value->data(), data_size); +#endif + memcpy(info->Data, value->data(), data_size); + } + return STATUS_SUCCESS; + + default: +#ifdef CHECKED + XTrace(L"QueryValueKey STATUS_INVALID_PARAMETER\n"); +#endif + return STATUS_INVALID_PARAMETER; + } +} + +NTSTATUS RegistryManager::NtQueryValueKey(HANDLE KeyHandle, PUNICODE_STRING ValueName, KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, PVOID KeyValueInformation, ULONG Length, PULONG ResultLength) +{ +#ifdef CHECKED + UnicodeString s(ValueName->Buffer, ValueName->Length / sizeof(wchar_t)); + XTrace(L"->NtQueryValueKey %p %s KeyValueInformationClass=%d Length=%d\n", KeyHandle, s.c_str(), KeyValueInformationClass, Length); +#endif + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetKey(KeyHandle); + if (object && object->ref()) { + if ((object->access() & KEY_QUERY_VALUE) == 0) + { +#ifdef CHECKED + XTrace(L"NtQueryValueKey STATUS_ACCESS_DENIED\n"); +#endif + return STATUS_ACCESS_DENIED; + } + + RegistryKey *key = static_cast<RegistryKey *>(object->ref()); + RegistryValue *value = key->GetValue(ValueName->Buffer); + if (value == NULL && append_mode_ == false) { + // \Registry\Machine\Software\Classes\... to + UnicodeString hklm = key->full_name(); + if (_wcsnicmp(hklm.c_str(), L"\\Registry\\Machine\\Software\\Classes\\", 35 /* SIZE */) == 0) { + // \REGISTRY\USER\<SID>_Classes\... + RegistryKey *ru = cache_.GetKey(L"\\REGISTRY\\USER"); + if (ru != NULL && ru->keys_size() == 1) { + ru = ru->key(0)->GetKey(hklm.c_str() + 35 /* SIZE */); + } + if (ru) { + value = ru->GetValue(ValueName->Buffer); +#ifdef CHECKED + XTrace(L"NtQueryValueKey map to hkCU %p\n", value); +#endif + } + } + } + if (value) { + try { + NTSTATUS ret = QueryValueKey(value, KeyValueInformationClass, KeyValueInformation, Length, ResultLength); +#ifdef CHECKED + XTrace(L"NtQueryValueKey ret=%p\n", ret); +#endif + return ret; + } catch(...) { +#ifdef CHECKED + XTrace(L"NtQueryValueKey STATUS_ACCESS_VIOLATION\n"); +#endif + return STATUS_ACCESS_VIOLATION; + } + } else if (!key->is_real()) { +#ifdef CHECKED + XTrace(L"NtQueryValueKey STATUS_OBJECT_NAME_NOT_FOUND\n"); +#endif + return STATUS_OBJECT_NAME_NOT_FOUND; + } + } + } + + NTSTATUS ret = TrueNtQueryValueKey(KeyHandle, ValueName, KeyValueInformationClass, KeyValueInformation, Length, ResultLength); +#ifdef CHECKED + XTrace(L"TrueNtQueryValueKey %p\n", ret); +#endif + return ret; +} + +NTSTATUS RegistryManager::NtDeleteKey(HANDLE KeyHandle) +{ +#ifdef CHECKED + XTrace(L"->NtDeleteKey %p\n", KeyHandle); +#endif + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetKey(KeyHandle); + if (object && object->ref()) { + RegistryKey *key = static_cast<RegistryKey *>(object->ref()); + objects_->DeleteRef(key); + if (key->owner()->DeleteKey(key)) + return STATUS_SUCCESS; + } + } + + if (append_mode_) { + // FIXME +#ifdef CHECKED + XTrace(L"TrueNtDeleteKey substed with STATUS_SUCCESS (append mode ON)\n"); +#endif + return STATUS_SUCCESS; + } + + NTSTATUS ret = TrueNtDeleteKey(KeyHandle); +#ifdef CHECKED + XTrace(L"TrueNtDeleteKey %p\n", ret); +#endif + return ret; +} + +NTSTATUS RegistryManager::QueryKey(RegistryKey *key, KEY_INFORMATION_CLASS KeyInformationClass, PVOID KeyInformation, ULONG Length, PULONG ResultLength) +{ + if (!key) + return STATUS_INVALID_PARAMETER; + + switch (KeyInformationClass) { + case KeyBasicInformation: + { + UnicodeString name = key->full_name(); + uint32_t min_size = offsetof(KEY_BASIC_INFORMATION, Name); + uint32_t name_size = static_cast<uint32_t>(name.size() * sizeof(wchar_t)); + uint32_t result_size = min_size + name_size; + if (ResultLength) + *ResultLength = result_size; + if (Length < min_size) + return STATUS_BUFFER_TOO_SMALL; + + KEY_BASIC_INFORMATION *info = static_cast<KEY_BASIC_INFORMATION *>(KeyInformation); + info->LastWriteTime.QuadPart = key->last_write_time(); + info->TitleIndex = 0; + info->NameLength = name_size; + + if (Length < result_size) + return STATUS_BUFFER_OVERFLOW; + + memcpy(info->Name, name.c_str(), name_size); + } + return STATUS_SUCCESS; + + case KeyNodeInformation: + { + UnicodeString name = key->full_name(); + uint32_t min_size = offsetof(KEY_NODE_INFORMATION, Name); + uint32_t name_size = static_cast<uint32_t>(name.size() * sizeof(wchar_t)); + uint32_t result_size = min_size + name_size; + if (ResultLength) + *ResultLength = result_size; + if (Length < min_size) + return STATUS_BUFFER_TOO_SMALL; + + KEY_NODE_INFORMATION *info = static_cast<KEY_NODE_INFORMATION *>(KeyInformation); + info->LastWriteTime.QuadPart = key->last_write_time(); + info->TitleIndex = 0; + info->ClassOffset = -1; + info->ClassLength = 0; + info->NameLength = name_size; + + if (Length < result_size) + return STATUS_BUFFER_OVERFLOW; + + memcpy(info->Name, name.c_str(), name_size); + } + return STATUS_SUCCESS; + + case KeyFullInformation: + { + uint32_t min_size = offsetof(KEY_FULL_INFORMATION, Class); + uint32_t result_size = min_size; + if (ResultLength) + *ResultLength = result_size; + if (Length < min_size) + return STATUS_BUFFER_TOO_SMALL; + + KEY_FULL_INFORMATION *info = static_cast<KEY_FULL_INFORMATION *>(KeyInformation); + info->LastWriteTime.QuadPart = key->last_write_time(); + info->TitleIndex = 0; + info->ClassOffset = -1; + info->ClassLength = 0; + info->SubKeys = static_cast<uint32_t>(key->keys_size()); + info->MaxNameLen = 0; + for (size_t i = 0; i < key->keys_size(); i++) { + uint32_t name_size = static_cast<uint32_t>(wcslen(key->key(i)->name()) * sizeof(wchar_t)); + if (info->MaxNameLen < name_size) + info->MaxNameLen = name_size; + } + info->MaxClassLen = 0; + info->Values = static_cast<uint32_t>(key->values_size()); + info->MaxValueNameLen = 0; + info->MaxValueDataLen = 0; + for (size_t i = 0; i < key->values_size(); i++) { + uint32_t name_size = static_cast<uint32_t>(wcslen(key->value(i)->name()) * sizeof(wchar_t)); + uint32_t data_size = key->value(i)->size(); + if (info->MaxValueNameLen < name_size) + info->MaxValueNameLen = name_size; + if (info->MaxValueDataLen < data_size) + info->MaxValueDataLen = data_size; + } + + if (Length < result_size) + return STATUS_BUFFER_OVERFLOW; + } + return STATUS_SUCCESS; + + case KeyNameInformation: + { + UnicodeString name = key->full_name(); + uint32_t min_size = offsetof(KEY_NAME_INFORMATION, Name); + uint32_t name_size = static_cast<uint32_t>(name.size() * sizeof(wchar_t)); + uint32_t result_size = min_size + name_size; + if (ResultLength) + *ResultLength = result_size; + if (Length < min_size) + return STATUS_BUFFER_TOO_SMALL; + + KEY_NAME_INFORMATION *info = static_cast<KEY_NAME_INFORMATION *>(KeyInformation); + info->NameLength = name_size; + + if (Length < result_size) + return STATUS_BUFFER_OVERFLOW; + + memcpy(info->Name, name.c_str(), name_size); + } + return STATUS_SUCCESS; + + case KeyCachedInformation: + { + UnicodeString name = key->full_name(); + uint32_t min_size = sizeof(KEY_CACHED_INFORMATION); + uint32_t result_size = min_size; + if (ResultLength) + *ResultLength = result_size; + if (Length < min_size) + return STATUS_BUFFER_TOO_SMALL; + + KEY_CACHED_INFORMATION *info = static_cast<KEY_CACHED_INFORMATION *>(KeyInformation); + info->LastWriteTime.QuadPart = key->last_write_time(); + info->TitleIndex = 0; + info->SubKeys = static_cast<uint32_t>(key->keys_size()); + info->MaxNameLen = 0; + for (size_t i = 0; i < key->keys_size(); i++) { + ULONG name_size = static_cast<ULONG>(wcslen(key->key(i)->name()) * sizeof(wchar_t)); + if (info->MaxNameLen < name_size) + info->MaxNameLen = name_size; + } + info->Values = static_cast<ULONG>(key->values_size()); + info->MaxValueNameLen = 0; + info->MaxValueDataLen = 0; + for (size_t i = 0; i < key->values_size(); i++) { + uint32_t name_size = static_cast<uint32_t>(wcslen(key->value(i)->name()) * sizeof(wchar_t)); + uint32_t data_size = static_cast<uint32_t>(key->value(i)->size()); + if (info->MaxValueNameLen < name_size) + info->MaxValueNameLen = name_size; + if (info->MaxValueDataLen < data_size) + info->MaxValueDataLen = data_size; + } + info->NameLength = static_cast<uint32_t>(name.size() * sizeof(wchar_t)); + + if (Length < result_size) + return STATUS_BUFFER_OVERFLOW; + } + return STATUS_SUCCESS; + + case KeyHandleTagsInformation: + { + uint32_t min_size = sizeof(KEY_HANDLE_TAGS_INFORMATION); + uint32_t result_size = min_size; + if (ResultLength) + *ResultLength = result_size; + if (Length < min_size) + return STATUS_BUFFER_TOO_SMALL; + + KEY_HANDLE_TAGS_INFORMATION *info = static_cast<KEY_HANDLE_TAGS_INFORMATION *>(KeyInformation); + info->HandleTags = 0; + } + return STATUS_SUCCESS; + + case KeyFlagsInformation: + case KeyVirtualizationInformation: + return STATUS_NOT_IMPLEMENTED; + + default: + return STATUS_INVALID_PARAMETER; + } +} + +static void ApplyDirtyHack(PVOID KeyInformation) +{ + KEY_HANDLE_TAGS_INFORMATION *info = static_cast<KEY_HANDLE_TAGS_INFORMATION *>(KeyInformation); + info->HandleTags = 0x601; +#ifdef CHECKED + XTrace(L"ApplyDirtyHack info->HandleTags=%d\n", info->HandleTags); +#endif +} + +NTSTATUS RegistryManager::NtQueryKey(HANDLE KeyHandle, KEY_INFORMATION_CLASS KeyInformationClass, PVOID KeyInformation, ULONG Length, PULONG ResultLength) +{ +#ifdef CHECKED + XTrace(L"->NtQueryKey %p KeyInformationClass=%d\n", KeyHandle, KeyInformationClass); +#endif + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetKey(KeyHandle); + if (object && object->ref()) { + if ((object->access() & KEY_QUERY_VALUE) == 0) + { + // Special case ( win2k/private/ntos/config/ntapi.c:NtQueryKey) + if(KeyInformationClass != KeyNameInformation || object->access() == 0) { +#ifdef CHECKED + XTrace(L"NtQueryKey STATUS_ACCESS_DENIED %p\n", object->access()); +#endif + return STATUS_ACCESS_DENIED; + } + } + + RegistryKey *key = static_cast<RegistryKey *>(object->ref()); + try { + NTSTATUS st = QueryKey(key, KeyInformationClass, KeyInformation, Length, ResultLength); +#ifdef CHECKED + XTrace(L"NtQueryKey st=%p, %d=%d\n", st, Length, ResultLength ? *ResultLength : 0); +#endif + if (KeyInformationClass == KeyHandleTagsInformation && st == S_OK && (object->access() & KEY_WOW64_32KEY) && append_mode_ && KeyInformation) + ApplyDirtyHack(KeyInformation); + return st; + } catch(...) { +#ifdef CHECKED + XTrace(L"NtQueryKey STATUS_ACCESS_VIOLATION\n"); +#endif + return STATUS_ACCESS_VIOLATION; + } + } + } + + NTSTATUS ret = TrueNtQueryKey(KeyHandle, KeyInformationClass, KeyInformation, Length, ResultLength); + if (KeyInformationClass == KeyHandleTagsInformation && ret == S_OK && append_mode_ && KeyInformation) + ApplyDirtyHack(KeyInformation); +#ifdef CHECKED + if(KeyInformationClass == 7) + { + KEY_HANDLE_TAGS_INFORMATION *info = static_cast<KEY_HANDLE_TAGS_INFORMATION *>(KeyInformation); + if (info) + XTrace(L"TrueNtQueryKey %p HandleTags=%p\n", ret, info->HandleTags); + } else if(KeyInformationClass == 3) + { + KEY_NAME_INFORMATION *info = static_cast<KEY_NAME_INFORMATION *>(KeyInformation); + if (info) + XTrace(L"TrueNtQueryKey %p info->Name=%s\n", ret, (UnicodeString(info->Name, info->NameLength)).c_str()); + } else + XTrace(L"TrueNtQueryKey %p\n", ret); +#endif + return ret; +} + +NTSTATUS RegistryManager::NtEnumerateValueKey(HANDLE KeyHandle, ULONG Index, KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, PVOID KeyValueInformation, ULONG Length, PULONG ResultLength) +{ +#ifdef CHECKED + XTrace(L"->NtEnumerateValueKey %p\n", KeyHandle); +#endif + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetKey(KeyHandle); + if (object && object->ref()) { + if ((object->access() & KEY_QUERY_VALUE) == 0) + { +#ifdef CHECKED + XTrace(L"NtEnumerateValueKey STATUS_ACCESS_DENIED\n"); +#endif + return STATUS_ACCESS_DENIED; + } + + RegistryKey *key = static_cast<RegistryKey *>(object->ref()); + if (Index >= key->values_size()) +#ifdef CHECKED + XTrace(L"NtEnumerateValueKey STATUS_NO_MORE_ENTRIES\n"); +#endif + return STATUS_NO_MORE_ENTRIES; + try { + NTSTATUS vret = QueryValueKey(key->value(Index), KeyValueInformationClass, KeyValueInformation, Length, ResultLength); +#ifdef CHECKED + XTrace(L"QueryValueKey %p\n", vret); +#endif + return vret; + } catch(...) { +#ifdef CHECKED + XTrace(L"NtEnumerateValueKey STATUS_ACCESS_VIOLATION\n"); +#endif + return STATUS_ACCESS_VIOLATION; + } + } + } + + NTSTATUS ret = TrueNtEnumerateValueKey(KeyHandle, Index, KeyValueInformationClass, KeyValueInformation, Length, ResultLength); +#ifdef CHECKED + XTrace(L"TrueNtEnumerateValueKey %p\n", ret); +#endif + return ret; +} + +NTSTATUS RegistryManager::NtEnumerateKey(HANDLE KeyHandle, ULONG Index, KEY_INFORMATION_CLASS KeyInformationClass, PVOID KeyInformation, ULONG Length, PULONG ResultLength) +{ +#ifdef CHECKED + XTrace(L"->NtEnumerateKey %p\n", KeyHandle); +#endif + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetKey(KeyHandle); + if (object && object->ref()) { + // a virtual key + if ((object->access() & KEY_ENUMERATE_SUB_KEYS) == 0) + { +#ifdef CHECKED + XTrace(L"NtEnumerateKey STATUS_ACCESS_DENIED\n"); +#endif + return STATUS_ACCESS_DENIED; + } + + RegistryKey *key = static_cast<RegistryKey *>(object->ref()); + if (Index >= key->keys_size()) +#ifdef CHECKED + XTrace(L"NtEnumerateKey STATUS_NO_MORE_ENTRIES\n"); +#endif + return STATUS_NO_MORE_ENTRIES; + try { + NTSTATUS vret = QueryKey(key->key(Index), KeyInformationClass, KeyInformation, Length, ResultLength); +#ifdef CHECKED + XTrace(L"QueryKey %p\n", vret); +#endif + return vret; + } catch(...) { +#ifdef CHECKED + XTrace(L"NtEnumerateKey STATUS_ACCESS_VIOLATION\n"); +#endif + return STATUS_ACCESS_VIOLATION; + } + } else { + // a real key +#ifdef CHECKED + XTrace(L"NtEnumerateKey real\n"); +#endif + uint32_t access; + if (object) + access = object->access(); + else { + PUBLIC_OBJECT_BASIC_INFORMATION info; + access = (NT_SUCCESS(TrueNtQueryObject(KeyHandle, ObjectBasicInformation, &info, sizeof(info), NULL))) ? info.GrantedAccess : 0; +#ifdef CHECKED + XTrace(L"TrueNtQueryObject.Access = %p\n", access); +#endif + } + if (access & KEY_ENUMERATE_SUB_KEYS) { + RegistryKey *key = NULL; + { + KEY_NAME_INFORMATION info; + DWORD size; + if (TrueNtQueryKey(KeyHandle, KeyNameInformation, &info, sizeof(info), &size) == STATUS_BUFFER_OVERFLOW) { + KEY_NAME_INFORMATION *data = reinterpret_cast<KEY_NAME_INFORMATION *>(new uint8_t[size]); + if (NT_SUCCESS(TrueNtQueryKey(KeyHandle, KeyNameInformation, data, size, &size))) + { + key = cache_.GetKey(UnicodeString(data->Name, data->NameLength / sizeof(wchar_t)).c_str()); +#ifdef CHECKED + XTrace(L"Cache used\n"); +#endif + } +#ifdef CHECKED + else + { + XTrace(L"Cache NOT used\n"); + } +#endif + delete [] data; + } + } + if (key) { + vector<RegistryKey *> children; + for (size_t i = 0; i < key->keys_size(); i++) { + RegistryKey *child = key->key(i); + if (!child->is_real()) + children.push_back(child); + } + if (Index < children.size()) { + try { + NTSTATUS vret = QueryKey(children[Index], KeyInformationClass, KeyInformation, Length, ResultLength); +#ifdef CHECKED + XTrace(L"QueryKey %p\n", vret); +#endif + return vret; + } catch(...) { +#ifdef CHECKED + XTrace(L"NtEnumerateKey STATUS_ACCESS_VIOLATION\n"); +#endif + return STATUS_ACCESS_VIOLATION; + } + } else { + Index -= static_cast<uint32_t>(children.size()); + } + } + } + } + } + + NTSTATUS ret = TrueNtEnumerateKey(KeyHandle, Index, KeyInformationClass, KeyInformation, Length, ResultLength); +#ifdef CHECKED + XTrace(L"TrueNtEnumerateKey %p\n", ret); +#endif + return ret; +} + +#endif // WIN_DRIVER
\ No newline at end of file diff --git a/runtime/registry_manager.h b/runtime/registry_manager.h new file mode 100644 index 0000000..c2a02fe --- /dev/null +++ b/runtime/registry_manager.h @@ -0,0 +1,299 @@ +#ifndef REGISTRY_MANAGER_H +#define REGISTRY_MANAGER_H + +struct REGISTRY_DIRECTORY { + uint32_t Reserved1; + uint32_t Reserved2; +}; + +typedef struct _KEY_VALUE_BASIC_INFORMATION { + ULONG TitleIndex; + ULONG Type; + ULONG NameLength; + WCHAR Name[1]; // Variable size +} KEY_VALUE_BASIC_INFORMATION, *PKEY_VALUE_BASIC_INFORMATION; + +typedef struct _KEY_VALUE_FULL_INFORMATION { + ULONG TitleIndex; + ULONG Type; + ULONG DataOffset; + ULONG DataLength; + ULONG NameLength; + WCHAR Name[1]; // Variable size +// Data[1]; // Variable size data not declared +} KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION; + +typedef struct _KEY_VALUE_PARTIAL_INFORMATION { + ULONG TitleIndex; + ULONG Type; + ULONG DataLength; + UCHAR Data[1]; // Variable size +} KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION; + +typedef struct _KEY_VALUE_PARTIAL_INFORMATION_ALIGN64 { + ULONG Type; + ULONG DataLength; + UCHAR Data[1]; // Variable size +} KEY_VALUE_PARTIAL_INFORMATION_ALIGN64, *PKEY_VALUE_PARTIAL_INFORMATION_ALIGN64; + +typedef enum _KEY_VALUE_INFORMATION_CLASS { + KeyValueBasicInformation, + KeyValueFullInformation, + KeyValuePartialInformation, + KeyValueFullInformationAlign64, + KeyValuePartialInformationAlign64, + MaxKeyValueInfoClass // MaxKeyValueInfoClass should always be the last enum +} KEY_VALUE_INFORMATION_CLASS; + +typedef struct _KEY_BASIC_INFORMATION { + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG NameLength; + WCHAR Name[1]; // Variable length string +} KEY_BASIC_INFORMATION, *PKEY_BASIC_INFORMATION; + +typedef struct _KEY_NODE_INFORMATION { + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG ClassOffset; + ULONG ClassLength; + ULONG NameLength; + WCHAR Name[1]; // Variable length string +// Class[1]; // Variable length string not declared +} KEY_NODE_INFORMATION, *PKEY_NODE_INFORMATION; + +typedef struct _KEY_FULL_INFORMATION { + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG ClassOffset; + ULONG ClassLength; + ULONG SubKeys; + ULONG MaxNameLen; + ULONG MaxClassLen; + ULONG Values; + ULONG MaxValueNameLen; + ULONG MaxValueDataLen; + WCHAR Class[1]; // Variable length +} KEY_FULL_INFORMATION, *PKEY_FULL_INFORMATION; + +typedef struct _KEY_NAME_INFORMATION { + ULONG NameLength; + WCHAR Name[1]; // Variable length +} KEY_NAME_INFORMATION, *PKEY_NAME_INFORMATION; + +typedef struct _KEY_CACHED_INFORMATION { + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG SubKeys; + ULONG MaxNameLen; + ULONG Values; + ULONG MaxValueNameLen; + ULONG MaxValueDataLen; + ULONG NameLength; +} KEY_CACHED_INFORMATION, *PKEY_CACHED_INFORMATION; + +typedef struct _KEY_HANDLE_TAGS_INFORMATION { + ULONG HandleTags; +} KEY_HANDLE_TAGS_INFORMATION, *PKEY_HANDLE_TAGS_INFORMATION; + +typedef enum _KEY_INFORMATION_CLASS { + KeyBasicInformation, + KeyNodeInformation, + KeyFullInformation, + KeyNameInformation, + KeyCachedInformation, + KeyFlagsInformation, + KeyVirtualizationInformation, + KeyHandleTagsInformation, + MaxKeyInfoClass // MaxKeyInfoClass should always be the last enum +} KEY_INFORMATION_CLASS; + +class RegistryValue +{ +public: + RegistryValue(const wchar_t *name); + ~RegistryValue(); + const wchar_t *name() const { return name_; } + uint32_t type() const { return type_; } + uint32_t size() const { return size_; } + void *data() const { return data_; } + void SetValue(uint32_t type, void *data, uint32_t size); +private: + wchar_t *name_; + uint32_t type_; + uint8_t *data_; + uint32_t size_; + + // no copy ctr or assignment op + RegistryValue(const RegistryValue &); + RegistryValue &operator =(const RegistryValue &); +}; + +class UnicodeString +{ +public: + UnicodeString() + : data_(NULL), size_(0) + { + data_ = new wchar_t[size_ + 1]; + data_[size_] = 0; + } + UnicodeString(const wchar_t *str) + : data_(NULL), size_(wcslen(str)) + { + data_ = new wchar_t[size_ + 1]; + memcpy(data_, str, size_ * sizeof(wchar_t)); + data_[size_] = 0; + } + UnicodeString(const wchar_t *str, size_t size) + : data_(NULL), size_(size) + { + data_ = new wchar_t[size_ + 1]; + memcpy(data_, str, size_ * sizeof(wchar_t)); + data_[size_] = 0; + } + UnicodeString(const UnicodeString &str) + : data_(NULL), size_(str.size_) + { + data_ = new wchar_t[size_ + 1]; + memcpy(data_, str.data_, size_ * sizeof(wchar_t)); + data_[size_] = 0; + } + UnicodeString &operator=(const UnicodeString &src) + { + if (&src != this) + { + delete [] data_; + size_ = src.size(); + data_ = new wchar_t[size_ + 1]; + memcpy(data_, src.c_str(), size_ * sizeof(wchar_t)); + data_[size_] = 0; + } + return *this; + } + ~UnicodeString() + { + delete [] data_; + } + size_t size() const { return size_; } + const wchar_t *c_str() const { return data_; } + UnicodeString &append(const wchar_t *str) { return append (str, wcslen(str)); } + UnicodeString &append(const wchar_t *str, size_t str_size) + { + size_t new_size = size_ + str_size; + wchar_t *new_data = new wchar_t[new_size + 1]; + memcpy(new_data, data_, size_ * sizeof(wchar_t)); + memcpy(new_data + size_, str, str_size * sizeof(wchar_t)); + new_data[new_size] = 0; + delete [] data_; + data_ = new_data; + size_ = new_size; + return *this; + } + UnicodeString &operator + (wchar_t c) { return append(&c, 1); } + UnicodeString &operator + (const wchar_t *str) { return append(str, wcslen(str)); } + bool operator == (const wchar_t *str) const { return wcscmp(c_str(), str) == 0; } +private: + wchar_t *data_; + size_t size_; +}; + +class RegistryKey +{ +public: + RegistryKey(); + RegistryKey(RegistryKey *owner, const wchar_t *name, bool is_real); + ~RegistryKey(); + RegistryKey *GetKey(const wchar_t *name) const; + RegistryKey *AddKey(const wchar_t *name, bool is_real, bool *is_exists); + bool DeleteKey(RegistryKey *key); + const wchar_t *name() const { return name_; } + UnicodeString full_name() const; + void SetValue(wchar_t *name, uint32_t type, void *data, uint32_t size); + bool DeleteValue(wchar_t *name); + RegistryValue *GetValue(const wchar_t *name) const; + bool is_real() const { return is_real_; } + void set_is_wow(bool value) { is_wow_ = value; } + RegistryKey *owner() const { return owner_; } + RegistryKey *key(size_t index) const { return keys_[index]; } + size_t keys_size() const { return keys_.size(); } + RegistryValue *value(size_t index) const { return values_[index]; } + size_t values_size() const { return values_.size(); } + uint64_t last_write_time() const { return last_write_time_; } +private: + RegistryKey *GetChild(const wchar_t *name) const; + RegistryKey *AddChild(const wchar_t *name, bool is_real, bool *is_exists); + RegistryValue *AddValue(wchar_t *value_name); + bool is_wow_node(const wchar_t *name) const; + wchar_t *name_; + RegistryKey *owner_; + bool is_real_; + bool is_wow_; + vector<RegistryKey *> keys_; + vector<RegistryValue *> values_; + uint64_t last_write_time_; + + // no copy ctr or assignment op + RegistryKey(const RegistryKey &); + RegistryKey &operator =(const RegistryKey &); +}; + +class VirtualObjectList; +class RegistryManager +{ +public: + RegistryManager(const uint8_t *data, HMODULE instance, const uint8_t *key, VirtualObjectList *objects); + void HookAPIs(HookManager &hook_manager); + void UnhookAPIs(HookManager &hook_manager); + void BeginRegisterServer(); + void EndRegisterServer(); + NTSTATUS NtSetValueKey(HANDLE KeyHandle, PUNICODE_STRING ValueName, ULONG TitleIndex, ULONG Type, PVOID Data, ULONG DataSize); + NTSTATUS NtDeleteValueKey(HANDLE KeyHandle, PUNICODE_STRING ValueName); + NTSTATUS NtCreateKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, ULONG TitleIndex, PUNICODE_STRING Class, ULONG CreateOptions, PULONG Disposition); + NTSTATUS NtQueryValueKey(HANDLE KeyHandle, PUNICODE_STRING ValueName, KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, PVOID KeyValueInformation, ULONG Length, PULONG ResultLength); + NTSTATUS NtOpenKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes); + NTSTATUS NtOpenKeyEx(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, ULONG OpenOptions); + NTSTATUS NtDeleteKey(HANDLE KeyHandle); + NTSTATUS NtQueryKey(HANDLE KeyHandle, KEY_INFORMATION_CLASS KeyInformationClass, PVOID KeyInformation, ULONG Length, PULONG ResultLength); + NTSTATUS NtEnumerateValueKey(HANDLE KeyHandle, ULONG Index, KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, PVOID KeyValueInformation, ULONG Length, PULONG ResultLength); + NTSTATUS NtEnumerateKey(HANDLE KeyHandle, ULONG Index, KEY_INFORMATION_CLASS KeyInformationClass, PVOID KeyInformation, ULONG Length, PULONG ResultLength); +private: + NTSTATUS TrueNtSetValueKey(HANDLE KeyHandle, PUNICODE_STRING ValueName, ULONG TitleIndex, ULONG Type, PVOID Data, ULONG DataSize); + NTSTATUS TrueNtDeleteValueKey(HANDLE KeyHandle, PUNICODE_STRING ValueName); + NTSTATUS TrueNtCreateKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, ULONG TitleIndex, PUNICODE_STRING Class, ULONG CreateOptions, PULONG Disposition); + NTSTATUS TrueNtQueryValueKey(HANDLE KeyHandle, PUNICODE_STRING ValueName, KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, PVOID KeyValueInformation, ULONG Length, PULONG ResultLength); + NTSTATUS TrueNtOpenKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes); + NTSTATUS TrueNtOpenKeyEx(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, ULONG OpenOptions); + NTSTATUS TrueNtDeleteKey(HANDLE KeyHandle); + NTSTATUS TrueNtQueryKey(HANDLE KeyHandle, KEY_INFORMATION_CLASS KeyInformationClass, PVOID KeyInformation, ULONG Length, PULONG ResultLength); + NTSTATUS TrueNtEnumerateValueKey(HANDLE KeyHandle, ULONG Index, KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, PVOID KeyValueInformation, ULONG Length, PULONG ResultLength); + NTSTATUS TrueNtEnumerateKey(HANDLE KeyHandle, ULONG Index, KEY_INFORMATION_CLASS KeyInformationClass, PVOID KeyInformation, ULONG Length, PULONG ResultLength); + NTSTATUS TrueNtQueryObject(HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength); + REGISTRY_DIRECTORY DecryptDirectory(const REGISTRY_DIRECTORY *directory_enc) const; + RegistryKey *GetRootKey(HANDLE root, uint32_t *access, bool can_create); + NTSTATUS QueryValueKey(RegistryValue *value, KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, PVOID KeyValueInformation, ULONG Length, PULONG ResultLength); + NTSTATUS QueryKey(RegistryKey *key, KEY_INFORMATION_CLASS KeyInformationClass, PVOID KeyInformation, ULONG Length, PULONG ResultLength); + + HMODULE instance_; + const uint8_t *data_; + uint32_t key_; + void *nt_set_value_key_; + void *nt_delete_value_key_; + void *nt_create_key_; + void *nt_open_key_; + void *nt_open_key_ex_; + void *nt_query_value_key_; + void *nt_delete_key_; + void *nt_query_key_; + void *nt_enumerate_value_key_; + void *nt_enumerate_key_; + RegistryKey cache_; + VirtualObjectList *objects_; + bool append_mode_; + + // no copy ctr or assignment op + RegistryManager(const RegistryManager &); + RegistryManager &operator =(const RegistryManager &); +}; + +#endif
\ No newline at end of file diff --git a/runtime/resource_manager.cc b/runtime/resource_manager.cc new file mode 100644 index 0000000..ca9ed3d --- /dev/null +++ b/runtime/resource_manager.cc @@ -0,0 +1,1022 @@ +#include "common.h" +#include "objects.h" + +#ifdef WIN_DRIVER +typedef BOOL (WINAPI *ENUMRESNAMEPROCA)(HMODULE hModule, LPCSTR lpType, LPSTR lpName, LONG_PTR lParam); +typedef BOOL (WINAPI *ENUMRESNAMEPROCW)(HMODULE hModule, LPCWSTR lpType, LPWSTR lpName, LONG_PTR lParam); +typedef BOOL (WINAPI *ENUMRESLANGPROCA)(HMODULE hModule, LPCSTR lpType, LPCSTR lpName, WORD wLanguage, LONG_PTR lParam); +typedef BOOL (WINAPI *ENUMRESLANGPROCW)(HMODULE hModule, LPCWSTR lpType, LPCWSTR lpName, WORD wLanguage, LONG_PTR lParam); +typedef BOOL (WINAPI *ENUMRESTYPEPROCA)(HMODULE hModule, LPSTR lpType, LONG_PTR lParam); +typedef BOOL (WINAPI *ENUMRESTYPEPROCW)(HMODULE hModule, LPWSTR lpType, LONG_PTR lParam); +#else +#include "core.h" +#include "crypto.h" +#include "resource_manager.h" +#include "hook_manager.h" +#include "utils.h" +#endif + +/** + * exported functions + */ + +HGLOBAL WINAPI ExportedLoadResource(HMODULE module, HRSRC res_info) +{ +#ifdef WIN_DRIVER + return NULL; +#else + ResourceManager *resource_manager = Core::Instance()->resource_manager(); + return resource_manager ? resource_manager->LoadResource(module, res_info) : NULL; +#endif +} + +HRSRC WINAPI ExportedFindResourceA(HMODULE module, LPCSTR name, LPCSTR type) +{ +#ifdef WIN_DRIVER + return NULL; +#else + ResourceManager *resource_manager = Core::Instance()->resource_manager(); + return resource_manager ? resource_manager->FindResourceA(module, name, type) : NULL; +#endif +} + +HRSRC WINAPI ExportedFindResourceExA(HMODULE module, LPCSTR type, LPCSTR name, WORD language) +{ +#ifdef WIN_DRIVER + return NULL; +#else + ResourceManager *resource_manager = Core::Instance()->resource_manager(); + return resource_manager ? resource_manager->FindResourceExA(module, type, name, language) : NULL; +#endif +} + +HRSRC WINAPI ExportedFindResourceW(HMODULE module, LPCWSTR name, LPCWSTR type) +{ +#ifdef WIN_DRIVER + return NULL; +#else + ResourceManager *resource_manager = Core::Instance()->resource_manager(); + return resource_manager ? resource_manager->FindResourceExW(module, type, name, 0) : NULL; +#endif +} + +HRSRC WINAPI ExportedFindResourceExW(HMODULE module, LPCWSTR type, LPCWSTR name, WORD language) +{ +#ifdef WIN_DRIVER + return NULL; +#else + ResourceManager *resource_manager = Core::Instance()->resource_manager(); + return resource_manager ? resource_manager->FindResourceExW(module, type, name, language) : NULL; +#endif +} + +int WINAPI ExportedLoadStringA(HMODULE module, UINT id, LPSTR buffer, int buffer_max) +{ +#ifdef WIN_DRIVER + return 0; +#else + ResourceManager *resource_manager = Core::Instance()->resource_manager(); + return resource_manager ? resource_manager->LoadStringA(module, id, buffer, buffer_max) : 0; +#endif +} + +int WINAPI ExportedLoadStringW(HMODULE module, UINT id, LPWSTR buffer, int buffer_max) +{ +#ifdef WIN_DRIVER + return 0; +#else + ResourceManager *resource_manager = Core::Instance()->resource_manager(); + return resource_manager ? resource_manager->LoadStringW(module, id, buffer, buffer_max) : 0; +#endif +} + +BOOL WINAPI ExportedEnumResourceNamesA(HMODULE module, LPCSTR type, ENUMRESNAMEPROCA enum_func, LONG_PTR param) +{ +#ifdef WIN_DRIVER + return FALSE; +#else + ResourceManager *resource_manager = Core::Instance()->resource_manager(); + return resource_manager ? resource_manager->EnumResourceNamesA(module, type, enum_func, param) : FALSE; +#endif +} + +BOOL WINAPI ExportedEnumResourceNamesW(HMODULE module, LPCWSTR type, ENUMRESNAMEPROCW enum_func, LONG_PTR param) +{ +#ifdef WIN_DRIVER + return FALSE; +#else + ResourceManager *resource_manager = Core::Instance()->resource_manager(); + return resource_manager ? resource_manager->EnumResourceNamesW(module, type, enum_func, param) : FALSE; +#endif +} + +BOOL WINAPI ExportedEnumResourceLanguagesA(HMODULE module, LPCSTR type, LPCSTR name, ENUMRESLANGPROCA enum_func, LONG_PTR param) +{ +#ifdef WIN_DRIVER + return FALSE; +#else + ResourceManager *resource_manager = Core::Instance()->resource_manager(); + return resource_manager ? resource_manager->EnumResourceLanguagesA(module, type, name, enum_func, param) : FALSE; +#endif +} + +BOOL WINAPI ExportedEnumResourceLanguagesW(HMODULE module, LPCWSTR type, LPCWSTR name, ENUMRESLANGPROCW enum_func, LONG_PTR param) +{ +#ifdef WIN_DRIVER + return FALSE; +#else + ResourceManager *resource_manager = Core::Instance()->resource_manager(); + return resource_manager ? resource_manager->EnumResourceLanguagesW(module, type, name, enum_func, param) : FALSE; +#endif +} + +BOOL WINAPI ExportedEnumResourceTypesA(HMODULE module, ENUMRESTYPEPROCA enum_func, LONG_PTR param) +{ +#ifdef WIN_DRIVER + return FALSE; +#else + ResourceManager *resource_manager = Core::Instance()->resource_manager(); + return resource_manager ? resource_manager->EnumResourceTypesA(module, enum_func, param) : FALSE; +#endif +} + +BOOL WINAPI ExportedEnumResourceTypesW(HMODULE module, ENUMRESTYPEPROCW enum_func, LONG_PTR param) +{ +#ifdef WIN_DRIVER + return FALSE; +#else + ResourceManager *resource_manager = Core::Instance()->resource_manager(); + return resource_manager ? resource_manager->EnumResourceTypesW(module, enum_func, param) : FALSE; +#endif +} + +#ifdef WIN_DRIVER +#else +/** + * hooked functions + */ + +int WINAPI HookedLoadStringA(HMODULE module, UINT id, LPSTR buffer, int buffer_max) +{ + ResourceManager *resource_manager = Core::Instance()->resource_manager(); + return resource_manager->LoadStringA(module, id, buffer, buffer_max); +} + +int WINAPI HookedLoadStringW(HMODULE module, UINT id, LPWSTR buffer, int buffer_max) +{ + ResourceManager *resource_manager = Core::Instance()->resource_manager(); + return resource_manager->LoadStringW(module, id, buffer, buffer_max); +} + +NTSTATUS WINAPI HookedLdrFindResource_U(HMODULE module, const LDR_RESOURCE_INFO *res_info, ULONG level, const IMAGE_RESOURCE_DATA_ENTRY **entry) +{ + ResourceManager *resource_manager = Core::Instance()->resource_manager(); + return resource_manager->LdrFindResource_U(module, res_info, level, entry); +} + +NTSTATUS WINAPI HookedLdrAccessResource(HMODULE module, const IMAGE_RESOURCE_DATA_ENTRY *entry, void **res, ULONG *size) +{ + ResourceManager *resource_manager = Core::Instance()->resource_manager(); + return resource_manager->LdrAccessResource(module, entry, res, size); +} + +/** + * ResourceManager + */ + +ResourceManager::ResourceManager(const uint8_t *data, HMODULE instance, const uint8_t *key) + : instance_(instance) + , data_(data) + , load_resource_(NULL) + , load_string_a_(NULL) + , load_string_w_(NULL) + , load_string_a_kernel_(NULL) + , load_string_w_kernel_(NULL) + , ldr_find_resource_u_(NULL) + , ldr_access_resource_(NULL) + , get_thread_ui_language_(NULL) +{ + CriticalSection::Init(critical_section_); + key_ = *(reinterpret_cast<const uint32_t *>(key)); + HMODULE dll = GetModuleHandleA(VMProtectDecryptStringA("kernel32.dll")); + if (dll) + get_thread_ui_language_ = InternalGetProcAddress(dll, VMProtectDecryptStringA("GetThreadUILanguage")); +} + +ResourceManager::~ResourceManager() +{ + CriticalSection::Free(critical_section_); +} + +void ResourceManager::HookAPIs(HookManager &hook_manager) +{ + hook_manager.Begin(); + HMODULE dll = GetModuleHandleA(VMProtectDecryptStringA("ntdll.dll")); + ldr_find_resource_u_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("LdrFindResource_U"), &HookedLdrFindResource_U); + ldr_access_resource_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("LdrAccessResource"), &HookedLdrAccessResource); + dll = GetModuleHandleA(VMProtectDecryptStringA("user32.dll")); + load_string_a_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("LoadStringA"), &HookedLoadStringA); + load_string_w_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("LoadStringW"), &HookedLoadStringW); + dll = GetModuleHandleA(VMProtectDecryptStringA("kernelbase.dll")); + if (dll) { + load_string_a_kernel_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("LoadStringA"), &HookedLoadStringA); + load_string_w_kernel_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("LoadStringW"), &HookedLoadStringW); + } + hook_manager.End(); +} + +void ResourceManager::UnhookAPIs(HookManager &hook_manager) +{ + hook_manager.Begin(); + hook_manager.UnhookAPI(ldr_find_resource_u_); + hook_manager.UnhookAPI(ldr_access_resource_); + hook_manager.UnhookAPI(load_string_a_); + hook_manager.UnhookAPI(load_string_w_); + if (load_string_a_kernel_) { + hook_manager.UnhookAPI(load_string_a_kernel_); + hook_manager.UnhookAPI(load_string_w_kernel_); + } + hook_manager.End(); +} + +int __forceinline ResourceManager::TrueLoadStringA(HMODULE module, UINT id, LPSTR buffer, int buffer_max) +{ + typedef int (WINAPI tLoadStringA)(HMODULE module, UINT id, LPSTR buffer, int buffer_max); + return reinterpret_cast<tLoadStringA *>(load_string_a_)(module, id, buffer, buffer_max); +} + +int __forceinline ResourceManager::TrueLoadStringW(HMODULE module, UINT id, LPWSTR buffer, int buffer_max) +{ + typedef int (WINAPI tLoadStringW)(HMODULE module, UINT id, LPWSTR buffer, int buffer_max); + return reinterpret_cast<tLoadStringW *>(load_string_w_)(module, id, buffer, buffer_max); +} + +NTSTATUS __forceinline ResourceManager::TrueLdrFindResource_U(HMODULE module, const LDR_RESOURCE_INFO *res_info, ULONG level, const IMAGE_RESOURCE_DATA_ENTRY **entry) +{ + typedef int (WINAPI tLdrFindResource_U)(HMODULE module, const LDR_RESOURCE_INFO *res_info, ULONG level, const IMAGE_RESOURCE_DATA_ENTRY **entry); + return reinterpret_cast<tLdrFindResource_U *>(ldr_find_resource_u_)(module, res_info, level, entry); +} + +NTSTATUS __forceinline ResourceManager::TrueLdrAccessResource(HMODULE module, const IMAGE_RESOURCE_DATA_ENTRY *entry, void **res, ULONG *size) +{ + typedef int (WINAPI tLdrAccessResource)(HMODULE module, const IMAGE_RESOURCE_DATA_ENTRY *pEntry, void **pRes, ULONG *pSize); + return reinterpret_cast<tLdrAccessResource *>(ldr_access_resource_)(module, entry, res, size); +} + +HGLOBAL ResourceManager::InternalLoadResource(HMODULE module, HRSRC res_info) +{ + if (!module) + module = GetModuleHandle(NULL); + + if (module == instance_) { + CriticalSection cs(critical_section_); + + size_t i = resources_.IndexByHandle(res_info); + if (i != -1) + return resources_[i]->Decrypt(instance_, key_); + } + return NULL; +} + +HGLOBAL ResourceManager::LoadResource(HMODULE module, HRSRC res_info) +{ + HGLOBAL res = InternalLoadResource(module, res_info); + if (res) + return res; + return ::LoadResource(module, res_info); +} + +HRSRC ResourceManager::InternalFindResourceExW(HMODULE module, LPCWSTR type, LPCWSTR name, WORD language) +{ + if (!module) + module = GetModuleHandle(NULL); + + if (module == instance_) { + const RESOURCE_DATA_ENTRY *entry_enc = reinterpret_cast<const RESOURCE_DATA_ENTRY *>(FindResourceEntry(type, name, language)); + if (entry_enc) { + CriticalSection cs(critical_section_); + + size_t i = resources_.IndexByEntry(entry_enc); + if (i != -1) + return resources_[i]->handle(); + + return resources_.Add(entry_enc, key_)->handle(); + } + } + return NULL; +} + +BOOL CreateResourceName(LPCWSTR src, LPWSTR &dst) +{ + if (IS_INTRESOURCE(src)) { + dst = MAKEINTRESOURCEW(LOWORD(src)); + return TRUE; + } + + if (src[0] == L'#') { + ULONG value = wcstoul(src + 1, NULL, 10); + if (HIWORD(value)) + return FALSE; + dst = MAKEINTRESOURCEW(value); + return TRUE; + } + + size_t len = wcslen(src); + dst = new wchar_t[len + 1]; + wcscpy_s(dst, len + 1, src); + CharUpperBuffW(dst, static_cast<DWORD>(len)); + return TRUE; +} + +BOOL CreateResourceName(LPCSTR src, LPWSTR &dst) +{ + if (IS_INTRESOURCE(src)) { + dst = MAKEINTRESOURCEW(LOWORD(src)); + return TRUE; + } + + if (src[0] == '#') { + ULONG value = strtoul(src + 1, NULL, 10); + if (HIWORD(value)) + return FALSE; + dst = MAKEINTRESOURCEW(value); + return TRUE; + } + + int size = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0); + if (size == 0) + return FALSE; + dst = new wchar_t[size]; + int size2 = MultiByteToWideChar(CP_ACP, 0, src, -1, dst, size); + CharUpperBuffW(dst, static_cast<DWORD>(size2)); + return TRUE; +} + +void FreeResourceName(LPCWSTR src) +{ + if (!IS_INTRESOURCE(src)) + delete [] src; +} + +HRSRC ResourceManager::FindResourceExW(HMODULE module, LPCWSTR type, LPCWSTR name, WORD language) +{ + if (!module) + module = GetModuleHandle(NULL); + + if (module == instance_) { + LPWSTR new_type = NULL; + LPWSTR new_name = NULL; + HRSRC res; + + if (CreateResourceName(type, new_type) && CreateResourceName(name, new_name)) { + res = InternalFindResourceExW(module, new_type, new_name, language); + } else { + res = NULL; + } + + FreeResourceName(new_type); + FreeResourceName(new_name); + + if (res) + return res; + } + return ::FindResourceExW(module, type, name, language); +} + +HRSRC ResourceManager::FindResourceW(HMODULE module, LPCWSTR name, LPCWSTR type) +{ + return FindResourceExW(module, type, name, 0); +} + +HRSRC ResourceManager::FindResourceExA(HMODULE module, LPCSTR type, LPCSTR name, WORD language) +{ + if (!module) + module = GetModuleHandle(NULL); + + if (module == instance_) { + LPWSTR new_type = NULL; + LPWSTR new_name = NULL; + HRSRC res; + + if (CreateResourceName(type, new_type) && CreateResourceName(name, new_name)) { + res = FindResourceExW(module, new_type, new_name, language); + } else { + res = NULL; + } + + FreeResourceName(new_name); + FreeResourceName(new_type); + + if (res) + return res; + } + return ::FindResourceExA(module, type, name, language); +} + +HRSRC ResourceManager::FindResourceA(HMODULE module, LPCSTR name, LPCSTR type) +{ + return FindResourceExA(module, type, name, 0); +} + +RESOURCE_DIRECTORY ResourceManager::DecryptDirectory(const RESOURCE_DIRECTORY *directory_enc) const +{ + RESOURCE_DIRECTORY res; + res.NumberOfNamedEntries = directory_enc->NumberOfNamedEntries ^ key_; + res.NumberOfIdEntries = directory_enc->NumberOfIdEntries ^ key_; + return res; +} + +RESOURCE_DIRECTORY_ENTRY ResourceManager::DecryptDirectoryEntry(const RESOURCE_DIRECTORY_ENTRY *entry_enc) const +{ + RESOURCE_DIRECTORY_ENTRY res; + res.Name = entry_enc->Name ^ key_; + res.OffsetToData = entry_enc->OffsetToData ^ key_; + return res; +} + +const RESOURCE_DIRECTORY *ResourceManager::FindEntryById(const RESOURCE_DIRECTORY *directory_enc, WORD id, DWORD dir_type) +{ + const RESOURCE_DIRECTORY_ENTRY *entry_enc = reinterpret_cast<const RESOURCE_DIRECTORY_ENTRY *>(directory_enc + 1); + + RESOURCE_DIRECTORY directory = DecryptDirectory(directory_enc); + int min = directory.NumberOfNamedEntries; + int max = min + directory.NumberOfIdEntries - 1; + + while (min <= max) { + int i = (min + max) / 2; + RESOURCE_DIRECTORY_ENTRY entry = DecryptDirectoryEntry(&entry_enc[i]); + if (entry.Id == id) { + if (entry.DataIsDirectory == dir_type) + return reinterpret_cast<const RESOURCE_DIRECTORY *>(data_ + entry.OffsetToDirectory); + break; + } + if (entry.Id > id) { + max = i - 1; + } else { + min = i + 1; + } + } + return NULL; +} + +int ResourceManager::CompareStringEnc(LPCWSTR name, LPCWSTR str_enc) const +{ + for (size_t i = 0; ;i++) { + wchar_t c = static_cast<wchar_t>(str_enc[i] ^ (_rotl32(key_, static_cast<int>(i)) + i)); + int res = name[i] - c; + if (res) + return (res < 0) ? -1 : 1; + if (!name[i]) + break; + } + return 0; +} + +LPWSTR ResourceManager::DecryptStringW(LPCWSTR str_enc) const +{ + size_t len = 0; + while (true) { + wchar_t c = static_cast<wchar_t>(str_enc[len] ^ (_rotl32(key_, static_cast<int>(len)) + len)); + len++; + if (!c) + break; + } + + LPWSTR res = new wchar_t[len]; + for (size_t i = 0; i < len; i++) { + res[i] = static_cast<wchar_t>(str_enc[i] ^ (_rotl32(key_, static_cast<int>(i)) + i)); + } + return res; +} + +LPSTR ResourceManager::DecryptStringA(LPCWSTR str_enc) const +{ + LPWSTR str = DecryptStringW(str_enc); + int len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL); + LPSTR res = new char[len]; + WideCharToMultiByte(CP_ACP, 0, str, -1, res, len, NULL, NULL); + delete [] str; + return res; +} + +const RESOURCE_DIRECTORY *ResourceManager::FindEntryByName(const RESOURCE_DIRECTORY *directory_enc, LPCWSTR name, DWORD dir_type) +{ + const RESOURCE_DIRECTORY_ENTRY *entry_enc = reinterpret_cast<const RESOURCE_DIRECTORY_ENTRY *>(directory_enc + 1); + RESOURCE_DIRECTORY directory = DecryptDirectory(directory_enc); + + int min = 0; + int max = directory.NumberOfNamedEntries - 1; + + while (min <= max) { + int i = (min + max) / 2; + RESOURCE_DIRECTORY_ENTRY entry = DecryptDirectoryEntry(&entry_enc[i]); + int res = CompareStringEnc(name, reinterpret_cast<LPCWSTR>(data_ + entry.NameOffset)); + if (!res) { + if (entry.DataIsDirectory == dir_type) + return reinterpret_cast<const RESOURCE_DIRECTORY *>(data_ + entry.OffsetToDirectory); + break; + } + if (res < 0) { + max = i - 1; + } else { + min = i + 1; + } + } + return NULL; +} + +const RESOURCE_DIRECTORY *ResourceManager::FindEntry(const RESOURCE_DIRECTORY *directory_enc, LPCWSTR name, DWORD dir_type) +{ + if (IS_INTRESOURCE(name)) + return FindEntryById(directory_enc, LOWORD(name), dir_type); + return FindEntryByName(directory_enc, name, dir_type); +} + +const RESOURCE_DIRECTORY *ResourceManager::FindFirstEntry(const RESOURCE_DIRECTORY *directory_enc, DWORD dir_type) +{ + const RESOURCE_DIRECTORY_ENTRY *entry_enc = reinterpret_cast<const RESOURCE_DIRECTORY_ENTRY *>(directory_enc + 1); + RESOURCE_DIRECTORY directory = DecryptDirectory(directory_enc); + + for (size_t i = 0; i < directory.NumberOfNamedEntries + directory.NumberOfIdEntries; i++) { + RESOURCE_DIRECTORY_ENTRY entry = DecryptDirectoryEntry(&entry_enc[i]); + if (entry.DataIsDirectory == dir_type) + return reinterpret_cast<const RESOURCE_DIRECTORY *>(data_ + entry.OffsetToDirectory); + } + return NULL; +} + +const RESOURCE_DIRECTORY *ResourceManager::FindResourceEntry(LPCWSTR type, LPCWSTR name, WORD language) +{ + if (!data_) + return NULL; + + size_t i, j; + + const RESOURCE_DIRECTORY *directory = reinterpret_cast<const RESOURCE_DIRECTORY *>(data_); + + for (i = 0; i < 2; i++){ + LPCWSTR value = (!i) ? type : name; + directory = FindEntry(directory, value, TRUE); + if (!directory) + return NULL; + } + + LANGID lang_list[10]; + size_t lang_count = 0; + + /* specified language */ + lang_list[lang_count++] = language; + + /* specified language with neutral sublanguage */ + lang_list[lang_count++] = MAKELANGID(PRIMARYLANGID(language), SUBLANG_NEUTRAL); + + /* neutral language with neutral sublanguage */ + lang_list[lang_count++] = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL); + + /* if no explicitly specified language, try some defaults */ + if (PRIMARYLANGID(language) == LANG_NEUTRAL) { + /* user defaults, unless SYS_DEFAULT sublanguage specified */ + if (SUBLANGID(language) != SUBLANG_SYS_DEFAULT) { + if (get_thread_ui_language_) { + typedef LANGID(WINAPI tGetThreadUILanguage)(); + lang_list[lang_count++] = reinterpret_cast<tGetThreadUILanguage *>(get_thread_ui_language_)(); + } + + /* current thread locale language */ + lang_list[lang_count++] = LANGIDFROMLCID(GetThreadLocale()); + + /* user locale language */ + lang_list[lang_count++] = LANGIDFROMLCID(GetUserDefaultLCID()); + + /* user locale language with neutral sublanguage */ + lang_list[lang_count++] = MAKELANGID(PRIMARYLANGID(GetUserDefaultLCID()), SUBLANG_NEUTRAL); + } + + /* now system defaults */ + + /* system locale language */ + lang_list[lang_count++] = LANGIDFROMLCID(GetSystemDefaultLCID()); + + /* system locale language with neutral sublanguage */ + lang_list[lang_count++] = MAKELANGID(PRIMARYLANGID(GetSystemDefaultLCID()), SUBLANG_NEUTRAL); + + /* English */ + lang_list[lang_count++] = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); + } + + for (i = 0; i < lang_count; i++) { + LANGID lang = lang_list[i]; + bool is_processed = false; + for (j = 0; j < i; j++) { + if (lang_list[j] == lang) { + is_processed = true; + break; + } + } + if (is_processed) + continue; + + if (const RESOURCE_DIRECTORY *entry = FindEntryById(directory, lang, FALSE)) + return entry; + } + + return FindFirstEntry(directory, FALSE); +} + +LPWSTR ResourceManager::InternalFindStringResource(HMODULE module, UINT id) +{ + HRSRC res_info = InternalFindResourceExW(module, LPWSTR(RT_STRING), MAKEINTRESOURCEW((LOWORD(id) >> 4) + 1), + 0); + if (!res_info) + return NULL; + + LPWSTR res = reinterpret_cast<LPWSTR>(InternalLoadResource(module, res_info)); + if (!res) + return NULL; + + IMAGE_RESOURCE_DATA_ENTRY *entry = reinterpret_cast<IMAGE_RESOURCE_DATA_ENTRY *>(res_info); + UINT res_size = entry->Size / sizeof(wchar_t); + UINT size = 0; + UINT str_len = 0; + + for (int i = id & 0x000f; i >= 0; i--) { + str_len = res[size] + 1; + size += str_len; + if (size > res_size) + return NULL; + } + + return (res + size - str_len); +} + +int ResourceManager::InternalLoadStringW(LPCWSTR res, LPWSTR buffer, int buffer_max) +{ + if (!buffer || (buffer_max < 0)) + return 0; + + if (buffer_max == 0) { + *(reinterpret_cast<LPCWSTR *>(buffer)) = res + 1; + return *res; + } + + int i = std::min<int>(buffer_max - 1, *res); + if (i > 0) { + memcpy(buffer, res + 1, i * sizeof (WCHAR)); + buffer[i] = 0; + return i; + } + if (buffer_max > 0) + buffer[0] = 0; + return 0; +} + +int ResourceManager::InternalLoadStringA(LPCWSTR res, LPSTR buffer, int buffer_max) +{ + if (!buffer || (buffer_max <= 0)) + return 0; + + int i = WideCharToMultiByte(CP_ACP, 0, res + 1, *res, NULL, 0, NULL, NULL); + if (i > 0) { + if (i > buffer_max - 1) { + LPSTR str = new char[i]; + i = std::min(buffer_max - 1, WideCharToMultiByte(CP_ACP, 0, res + 1, *res, str, i, NULL, NULL)); + memcpy(buffer, str, i * sizeof (CHAR)); + delete [] str; + } else { + i = WideCharToMultiByte(CP_ACP, 0, res + 1, *res, buffer, buffer_max - 1, NULL, NULL); + } + buffer[i] = 0; + return i; + } + if (buffer_max > 0) + buffer[0] = 0; + return 0; +} + +int ResourceManager::LoadStringA(HMODULE module, UINT uID, LPSTR buffer, int buffer_max) +{ + LPWSTR res = InternalFindStringResource(module, uID); + if (res) + return InternalLoadStringA(res, buffer, buffer_max); + return TrueLoadStringA(module, uID, buffer, buffer_max); +} + +int ResourceManager::LoadStringW(HMODULE module, UINT id, LPWSTR buffer, int buffer_max) +{ + LPWSTR res = InternalFindStringResource(module, id); + if (res) + return InternalLoadStringW(res, buffer, buffer_max); + return TrueLoadStringW(module, id, buffer, buffer_max); +} + +NTSTATUS ResourceManager::LdrFindResource_U(HMODULE module, const LDR_RESOURCE_INFO *res_info, ULONG level, const IMAGE_RESOURCE_DATA_ENTRY **entry) +{ + if (level == 3) { + HRSRC res = InternalFindResourceExW(module, res_info->Type, res_info->Name, res_info->Language); + if (res) { + *entry = reinterpret_cast<IMAGE_RESOURCE_DATA_ENTRY *>(res); + return 0; + } + } + return TrueLdrFindResource_U(module, res_info, level, entry); +} + +NTSTATUS ResourceManager::LdrAccessResource(HMODULE module, const IMAGE_RESOURCE_DATA_ENTRY *entry, void **res, ULONG *size) +{ + HGLOBAL h = InternalLoadResource(module, (HRSRC)entry); + if (h) { + if (res) + *res = h; + if (size) + *size = entry->Size; + return 0; + } + return TrueLdrAccessResource(module, entry, res, size); +} + +BOOL ResourceManager::EnumResourceNamesA(HMODULE module, LPCSTR type, ENUMRESNAMEPROCA enum_func, LONG_PTR param) +{ + if (!module) + module = GetModuleHandle(NULL); + + if (module == instance_) { + LPWSTR new_type = NULL; + const RESOURCE_DIRECTORY *directory_enc; + + if (CreateResourceName(type, new_type)) { + directory_enc = FindEntry(reinterpret_cast<const RESOURCE_DIRECTORY *>(data_), new_type, TRUE); + } else { + directory_enc = NULL; + } + FreeResourceName(new_type); + + if (directory_enc) { + const RESOURCE_DIRECTORY_ENTRY *entry_enc = reinterpret_cast<const RESOURCE_DIRECTORY_ENTRY *>(directory_enc + 1); + RESOURCE_DIRECTORY directory = DecryptDirectory(directory_enc); + for (size_t i = 0; i < directory.NumberOfNamedEntries + directory.NumberOfIdEntries; i++) { + RESOURCE_DIRECTORY_ENTRY entry = DecryptDirectoryEntry(&entry_enc[i]); + BOOL res; + if (entry.NameIsString) { + LPSTR name = DecryptStringA(reinterpret_cast<LPCWSTR>(data_ + entry.NameOffset)); + res = enum_func(module, type, name, param); + delete [] name; + } else { + res = enum_func(module, type, MAKEINTRESOURCEA(entry.Id), param); + } + + if (!res) + break; + } + return TRUE; + } + } + return ::EnumResourceNamesA(module, type, enum_func, param); +} + +BOOL ResourceManager::EnumResourceNamesW(HMODULE module, LPCWSTR type, ENUMRESNAMEPROCW enum_func, LONG_PTR param) +{ + if (!module) + module = GetModuleHandle(NULL); + + if (module == instance_) { + LPWSTR new_type = NULL; + const RESOURCE_DIRECTORY *directory_enc; + + if (CreateResourceName(type, new_type)) { + directory_enc = FindEntry(reinterpret_cast<const RESOURCE_DIRECTORY *>(data_), new_type, TRUE); + } else { + directory_enc = NULL; + } + FreeResourceName(new_type); + + if (directory_enc) { + const RESOURCE_DIRECTORY_ENTRY *entry_enc = reinterpret_cast<const RESOURCE_DIRECTORY_ENTRY *>(directory_enc + 1); + RESOURCE_DIRECTORY directory = DecryptDirectory(directory_enc); + for (size_t i = 0; i < directory.NumberOfNamedEntries + directory.NumberOfIdEntries; i++) { + RESOURCE_DIRECTORY_ENTRY entry = DecryptDirectoryEntry(&entry_enc[i]); + BOOL res; + if (entry.NameIsString) { + LPWSTR name = DecryptStringW(reinterpret_cast<LPCWSTR>(data_ + entry.NameOffset)); + res = enum_func(module, type, name, param); + delete [] name; + } else { + res = enum_func(module, type, MAKEINTRESOURCEW(entry.Id), param); + } + + if (!res) + break; + } + return TRUE; + } + } + return ::EnumResourceNamesW(module, type, enum_func, param); +} + +BOOL ResourceManager::EnumResourceLanguagesA(HMODULE module, LPCSTR type, LPCSTR name, ENUMRESLANGPROCA enum_func, LONG_PTR param) +{ + if (!module) + module = GetModuleHandle(NULL); + + if (module == instance_) { + const RESOURCE_DIRECTORY *directory_enc = reinterpret_cast<const RESOURCE_DIRECTORY *>(data_); + + for (size_t i = 0; i < 2; i++) { + LPWSTR value = NULL; + if (CreateResourceName((!i) ? type : name, value)) { + directory_enc = FindEntry(directory_enc, value, TRUE); + } else { + directory_enc = NULL; + } + + FreeResourceName(value); + + if (!directory_enc) + break; + } + + if (directory_enc) { + const RESOURCE_DIRECTORY_ENTRY *entry_enc = reinterpret_cast<const RESOURCE_DIRECTORY_ENTRY *>(directory_enc + 1); + RESOURCE_DIRECTORY directory = DecryptDirectory(directory_enc); + for (size_t i = 0; i < directory.NumberOfNamedEntries + directory.NumberOfIdEntries; i++) { + RESOURCE_DIRECTORY_ENTRY entry = DecryptDirectoryEntry(&entry_enc[i]); + if (!enum_func(module, type, name, entry.Id, param)) + break; + } + return TRUE; + } + } + return ::EnumResourceLanguagesA(module, type, name, enum_func, param); +} + +BOOL ResourceManager::EnumResourceLanguagesW(HMODULE module, LPCWSTR type, LPCWSTR name, ENUMRESLANGPROCW enum_func, LONG_PTR param) +{ + if (!module) + module = GetModuleHandle(NULL); + + if (module == instance_) { + const RESOURCE_DIRECTORY *directory_enc = reinterpret_cast<const RESOURCE_DIRECTORY *>(data_); + + for (size_t i = 0; i < 2; i++) { + LPWSTR value = NULL; + if (CreateResourceName((!i) ? type : name, value)) { + directory_enc = FindEntry(directory_enc, value, TRUE); + } else { + directory_enc = NULL; + } + + FreeResourceName(value); + + if (!directory_enc) + break; + } + + if (directory_enc) { + const RESOURCE_DIRECTORY_ENTRY *entry_enc = reinterpret_cast<const RESOURCE_DIRECTORY_ENTRY *>(directory_enc + 1); + RESOURCE_DIRECTORY directory = DecryptDirectory(directory_enc); + for (size_t i = 0; i < directory.NumberOfNamedEntries + directory.NumberOfIdEntries; i++) { + RESOURCE_DIRECTORY_ENTRY entry = DecryptDirectoryEntry(&entry_enc[i]); + if (!enum_func(module, type, name, entry.Id, param)) + break; + } + return TRUE; + } + } + return ::EnumResourceLanguagesW(module, type, name, enum_func, param); +} + +BOOL ResourceManager::EnumResourceTypesA(HMODULE module, ENUMRESTYPEPROCA enum_func, LONG_PTR param) +{ + if (!module) + module = GetModuleHandle(NULL); + + if (module == instance_) { + const RESOURCE_DIRECTORY *directory_enc = reinterpret_cast<const RESOURCE_DIRECTORY *>(data_); + const RESOURCE_DIRECTORY_ENTRY *entry_enc = reinterpret_cast<const RESOURCE_DIRECTORY_ENTRY *>(directory_enc + 1); + RESOURCE_DIRECTORY directory = DecryptDirectory(directory_enc); + for (size_t i = 0; i < directory.NumberOfNamedEntries + directory.NumberOfIdEntries; i++) { + RESOURCE_DIRECTORY_ENTRY entry = DecryptDirectoryEntry(&entry_enc[i]); + BOOL res; + if (entry.NameIsString) { + LPSTR type = DecryptStringA(reinterpret_cast<LPCWSTR>(data_ + entry.NameOffset)); + res = enum_func(module, type, param); + delete [] type; + } else { + res = enum_func(module, MAKEINTRESOURCEA(entry.Id), param); + } + + if (!res) + break; + } + } + return ::EnumResourceTypesA(module, enum_func, param); +} + +BOOL ResourceManager::EnumResourceTypesW(HMODULE module, ENUMRESTYPEPROCW enum_func, LONG_PTR param) +{ + if (!module) + module = GetModuleHandle(NULL); + + if (module == instance_) { + const RESOURCE_DIRECTORY *directory_enc = reinterpret_cast<const RESOURCE_DIRECTORY *>(data_); + const RESOURCE_DIRECTORY_ENTRY *entry_enc = reinterpret_cast<const RESOURCE_DIRECTORY_ENTRY *>(directory_enc + 1); + RESOURCE_DIRECTORY directory = DecryptDirectory(directory_enc); + for (size_t i = 0; i < directory.NumberOfNamedEntries + directory.NumberOfIdEntries; i++) { + RESOURCE_DIRECTORY_ENTRY entry = DecryptDirectoryEntry(&entry_enc[i]); + BOOL res; + if (entry.NameIsString) { + LPWSTR type = DecryptStringW(reinterpret_cast<LPCWSTR>(data_ + entry.NameOffset)); + res = enum_func(module, type, param); + delete [] type; + } else { + res = enum_func(module, MAKEINTRESOURCEW(entry.Id), param); + } + + if (!res) + break; + } + } + return ::EnumResourceTypesW(module, enum_func, param); +} + +/** + * VirtualResource + */ + +VirtualResource::VirtualResource(const RESOURCE_DATA_ENTRY *entry_enc, uint32_t key) + : entry_(entry_enc), address_(NULL) +{ + RESOURCE_DATA_ENTRY entry; + entry.OffsetToData = entry_enc->OffsetToData ^ key; + entry.Size = entry_enc->Size ^ key; + entry.CodePage = entry_enc->CodePage ^ key; + entry.Reserved = entry_enc->Reserved ^ key; + + handle_.OffsetToData = entry.OffsetToData; + handle_.CodePage = entry.CodePage; + handle_.Size = entry.Size; + handle_.Reserved = entry.Reserved; +} + +VirtualResource::~VirtualResource() +{ + delete [] address_; +} + +HGLOBAL VirtualResource::Decrypt(HMODULE instance, uint32_t key) +{ + if (!address_) { + address_ = new uint8_t[handle_.Size]; + uint8_t *source = reinterpret_cast<uint8_t *>(instance) + handle_.OffsetToData; + for (size_t i = 0; i < handle_.Size; i++) { + address_[i] = static_cast<uint8_t>(source[i] ^ (_rotl32(key, static_cast<int>(i)) + i)); + } + } + return static_cast<HGLOBAL>(address_); +} + +/** + * VirtualResourceList + */ + +VirtualResourceList::~VirtualResourceList() +{ + for (size_t i = 0; i < size(); i++) { + VirtualResource *resource = v_[i]; + delete resource; + } + v_.clear(); +} + +VirtualResource *VirtualResourceList::Add(const RESOURCE_DATA_ENTRY *entry, uint32_t key) +{ + VirtualResource *resource = new VirtualResource(entry, key); + v_.push_back(resource); + return resource; +} + +void VirtualResourceList::Delete(size_t index) +{ + VirtualResource *resource = v_[index]; + delete resource; + v_.erase(index); +} + +size_t VirtualResourceList::IndexByEntry(const RESOURCE_DATA_ENTRY *entry) const +{ + for (size_t i = 0; i < size(); i++) { + if (v_[i]->entry() == entry) + return i; + } + return -1; +} + +size_t VirtualResourceList::IndexByHandle(HRSRC handle) const +{ + for (size_t i = 0; i < size(); i++) { + if (v_[i]->handle() == handle) + return i; + } + return -1; +} + +#endif
\ No newline at end of file diff --git a/runtime/resource_manager.h b/runtime/resource_manager.h new file mode 100644 index 0000000..e2c44ac --- /dev/null +++ b/runtime/resource_manager.h @@ -0,0 +1,148 @@ +#ifndef RESOURCE_MANAGER_H +#define RESOURCE_MANAGER_H + +#pragma pack(push, 1) + +class CipherRC5; + +struct RESOURCE_DIRECTORY { + uint32_t NumberOfNamedEntries; + uint32_t NumberOfIdEntries; + // RESOURCE_DIRECTORY_ENTRY DirectoryEntries[]; +}; + +//#pragma warning(push) +//#pragma warning(disable:4201) // named type definition in parentheses +struct RESOURCE_DIRECTORY_ENTRY { + union { + struct { + uint32_t NameOffset:31; + uint32_t NameIsString:1; + } /*DUMMYSTRUCTNAME*/; + uint32_t Name; + uint16_t Id; + } /*DUMMYUNIONNAME*/; + union { + uint32_t OffsetToData; + struct { + uint32_t OffsetToDirectory:31; + uint32_t DataIsDirectory:1; + } /*DUMMYSTRUCTNAME2*/; + } /*DUMMYUNIONNAME2*/; +}; +//#pragma warning(pop) + +struct RESOURCE_DATA_ENTRY { + uint32_t OffsetToData; + uint32_t Size; + uint32_t CodePage; + uint32_t Reserved; +}; + +#pragma pack(pop) + +struct LDR_RESOURCE_INFO { + LPWSTR Type; + LPWSTR Name; + WORD Language; + }; + +class VirtualResource +{ +public: + VirtualResource(const RESOURCE_DATA_ENTRY *entry, uint32_t key); + ~VirtualResource(); + HGLOBAL Decrypt(HMODULE instance, uint32_t key); + const RESOURCE_DATA_ENTRY *entry() const { return entry_; } + HRSRC handle() const { return reinterpret_cast<HRSRC>(const_cast<IMAGE_RESOURCE_DATA_ENTRY *>(&handle_)); } +private: + const RESOURCE_DATA_ENTRY *entry_; + IMAGE_RESOURCE_DATA_ENTRY handle_; + uint8_t *address_; + + // no copy ctr or assignment op + VirtualResource(const VirtualResource &); + VirtualResource &operator =(const VirtualResource &); +}; + +class VirtualResourceList +{ +public: + ~VirtualResourceList(); + VirtualResource *Add(const RESOURCE_DATA_ENTRY *entry, uint32_t key); + void Delete(size_t index); + size_t IndexByEntry(const RESOURCE_DATA_ENTRY *entry) const; + size_t IndexByHandle(HRSRC handle) const; + VirtualResource *operator [] (size_t index) const { return v_[index]; } + size_t size() const { return v_.size(); } +private: + vector<VirtualResource *> v_; +}; + +class ResourceManager +{ +public: + ResourceManager(const uint8_t *data, HMODULE instance, const uint8_t *key); + ~ResourceManager(); + + void HookAPIs(HookManager &hook_manager); + void UnhookAPIs(HookManager &hook_manager); + + HGLOBAL LoadResource(HMODULE module, HRSRC res_info); + HRSRC FindResourceA(HMODULE module, LPCSTR name, LPCSTR type); + HRSRC FindResourceExA(HMODULE module, LPCSTR type, LPCSTR name, WORD language); + HRSRC FindResourceW(HMODULE module, LPCWSTR name, LPCWSTR type); + HRSRC FindResourceExW(HMODULE module, LPCWSTR type, LPCWSTR name, WORD language); + int LoadStringA(HMODULE module, UINT id, LPSTR buffer, int buffer_max); + int LoadStringW(HMODULE module, UINT id, LPWSTR buffer, int buffer_max); + NTSTATUS LdrFindResource_U(HMODULE module, const LDR_RESOURCE_INFO *res_info, ULONG level, const IMAGE_RESOURCE_DATA_ENTRY **entry); + NTSTATUS LdrAccessResource(HMODULE module, const IMAGE_RESOURCE_DATA_ENTRY *entry, void **res, ULONG *size); + BOOL EnumResourceNamesA(HMODULE module, LPCSTR type, ENUMRESNAMEPROCA enum_func, LONG_PTR param); + BOOL EnumResourceNamesW(HMODULE module, LPCWSTR type, ENUMRESNAMEPROCW enum_func, LONG_PTR param); + BOOL EnumResourceLanguagesA(HMODULE module, LPCSTR type, LPCSTR name, ENUMRESLANGPROCA enum_func, LONG_PTR param); + BOOL EnumResourceLanguagesW(HMODULE module, LPCWSTR type, LPCWSTR name, ENUMRESLANGPROCW enum_func, LONG_PTR param); + BOOL EnumResourceTypesA(HMODULE module, ENUMRESTYPEPROCA enum_func, LONG_PTR param); + BOOL EnumResourceTypesW(HMODULE module, ENUMRESTYPEPROCW enum_func, LONG_PTR param); +private: + RESOURCE_DIRECTORY DecryptDirectory(const RESOURCE_DIRECTORY *directory_enc) const; + RESOURCE_DIRECTORY_ENTRY DecryptDirectoryEntry(const RESOURCE_DIRECTORY_ENTRY *entry_enc) const; + int CompareStringEnc(LPCWSTR name, LPCWSTR str_enc) const; + LPWSTR DecryptStringW(LPCWSTR src_enc) const; + LPSTR DecryptStringA(LPCWSTR src_enc) const; + const RESOURCE_DIRECTORY *FindEntryById(const RESOURCE_DIRECTORY *directory, WORD id, DWORD dir_type); + const RESOURCE_DIRECTORY *FindEntryByName(const RESOURCE_DIRECTORY *directory, LPCWSTR name, DWORD dir_type); + const RESOURCE_DIRECTORY *FindEntry(const RESOURCE_DIRECTORY *directory, LPCWSTR name, DWORD dir_type); + const RESOURCE_DIRECTORY *FindFirstEntry(const RESOURCE_DIRECTORY *directory, DWORD dir_type); + const RESOURCE_DIRECTORY *FindResourceEntry(LPCWSTR type, LPCWSTR name, WORD language); + HRSRC InternalFindResourceExW(HMODULE module, LPCWSTR type, LPCWSTR name, WORD language); + HGLOBAL InternalLoadResource(HMODULE module, HRSRC res_info); + LPWSTR InternalFindStringResource(HMODULE module, UINT id); + int InternalLoadStringW(LPCWSTR res, LPWSTR buffer, int buffer_max); + int InternalLoadStringA(LPCWSTR res, LPSTR buffer, int buffer_max); + uint16_t DecryptWord(uint16_t value) const; + + int TrueLoadStringA(HMODULE module, UINT id, LPSTR buffer, int buffer_max); + int TrueLoadStringW(HMODULE module, UINT id, LPWSTR buffer, int buffer_max); + NTSTATUS TrueLdrFindResource_U(HMODULE module, const LDR_RESOURCE_INFO *res_info, ULONG level, const IMAGE_RESOURCE_DATA_ENTRY **entry); + NTSTATUS TrueLdrAccessResource(HMODULE module, const IMAGE_RESOURCE_DATA_ENTRY *entry, void **res, ULONG *size); + + HMODULE instance_; + uint32_t key_; + CRITICAL_SECTION critical_section_; + VirtualResourceList resources_; + const uint8_t *data_; + void *load_resource_; + void *load_string_a_; + void *load_string_w_; + void *load_string_a_kernel_; + void *load_string_w_kernel_; + void *ldr_find_resource_u_; + void *ldr_access_resource_; + void *get_thread_ui_language_; + + // no copy ctr or assignment op + ResourceManager(const ResourceManager &); + ResourceManager &operator =(const ResourceManager &); +}; + +#endif
\ No newline at end of file diff --git a/runtime/runtime.def b/runtime/runtime.def new file mode 100644 index 0000000..3d07ceb --- /dev/null +++ b/runtime/runtime.def @@ -0,0 +1,33 @@ +EXPORTS + SetupImage + FreeImage + ExportedDecryptString + ExportedFreeString + ExportedLoadResource + ExportedFindResourceA + ExportedFindResourceExA + ExportedFindResourceW + ExportedFindResourceExW + ExportedLoadStringA + ExportedLoadStringW + ExportedEnumResourceNamesA + ExportedEnumResourceNamesW + ExportedEnumResourceLanguagesA + ExportedEnumResourceLanguagesW + ExportedEnumResourceTypesA + ExportedEnumResourceTypesW + ExportedSetSerialNumber + ExportedGetSerialNumberState + ExportedGetSerialNumberData + ExportedGetCurrentHWID + ExportedActivateLicense + ExportedDeactivateLicense + ExportedGetOfflineActivationString + ExportedGetOfflineDeactivationString + ExportedIsValidImageCRC + ExportedIsDebuggerPresent + ExportedIsVirtualMachinePresent + ExportedDecryptBuffer + ExportedIsProtected + CalcCRC + LoaderData = loader_data
\ No newline at end of file diff --git a/runtime/string_manager.cc b/runtime/string_manager.cc new file mode 100644 index 0000000..e49d568 --- /dev/null +++ b/runtime/string_manager.cc @@ -0,0 +1,184 @@ +#include "objects.h" +#include "common.h" +#include "core.h" +#include "crypto.h" +#include "string_manager.h" + +/** + * exported functions + */ + +#ifdef VMP_GNU +EXPORT_API const void * WINAPI ExportedDecryptString(const void *str) __asm__ ("ExportedDecryptString"); +EXPORT_API bool WINAPI ExportedFreeString(const void *str) __asm__ ("ExportedFreeString"); +#endif + +const void * WINAPI ExportedDecryptString(const void *str) +{ + StringManager *string_manager = Core::Instance()->string_manager(); + return string_manager ? string_manager->DecryptString(str) : str; +} + +bool WINAPI ExportedFreeString(const void *str) +{ + StringManager *string_manager = Core::Instance()->string_manager(); + return string_manager ? string_manager->FreeString(str) : false; +} + +/** + * StringManager + */ + +StringManager::StringManager(const uint8_t *data, HMODULE instance, const uint8_t *key) + : data_(data), instance_(instance) +{ + CriticalSection::Init(critical_section_); + key_ = *(reinterpret_cast<const uint32_t *>(key)); + const STRING_DIRECTORY *directory_enc = reinterpret_cast<const STRING_DIRECTORY *>(data_); + STRING_DIRECTORY directory = DecryptDirectory(directory_enc); + size_ = directory.NumberOfEntries; + strings_ = new VirtualString*[size_]; + memset(strings_, 0, sizeof(VirtualString *) * size_); +} + +StringManager::~StringManager() +{ + for (size_t i = 0; i < size_; i++) { + delete strings_[i]; + } + delete [] strings_; + CriticalSection::Free(critical_section_); +} + +STRING_DIRECTORY StringManager::DecryptDirectory(const STRING_DIRECTORY *directory_enc) const +{ + STRING_DIRECTORY res; + res.NumberOfEntries = directory_enc->NumberOfEntries ^ key_; + return res; +} + +STRING_ENTRY StringManager::DecryptEntry(const STRING_ENTRY *entry_enc) const +{ + STRING_ENTRY res; + res.Id = entry_enc->Id ^ key_; + res.OffsetToData = entry_enc->OffsetToData ^ key_; + res.Size = entry_enc->Size ^ key_; + return res; +} + +size_t StringManager::IndexById(uint32_t id) const +{ + const STRING_ENTRY *entry_enc = reinterpret_cast<const STRING_ENTRY *>(data_ + sizeof(STRING_DIRECTORY)); + + int min = 0; + int max = (int)size_ - 1; + while (min <= max) { + int i = (min + max) / 2; + STRING_ENTRY entry = DecryptEntry(entry_enc + i); + if (entry.Id == id) { + return i; + } + if (entry.Id > id) { + max = i - 1; + } else { + min = i + 1; + } + } + return NOT_ID; +} + +const void *StringManager::DecryptString(const void *str) +{ + size_t id = reinterpret_cast<size_t>(str) - reinterpret_cast<size_t>(instance_); + if ((id >> 31) == 0) { + size_t i = IndexById(static_cast<uint32_t>(id)); + if (i != NOT_ID) { + CriticalSection cs(critical_section_); + VirtualString *string = strings_[i]; + if (!string) { + const STRING_ENTRY *entry_enc = reinterpret_cast<const STRING_ENTRY *>(data_ + sizeof(STRING_DIRECTORY)); + string = new VirtualString(entry_enc + i, instance_, key_); + strings_[i] = string; + } + return string->AcquirePointer(); + } + } + return str; +} + +size_t StringManager::IndexByAddress(const void *address) const +{ + for (size_t i = 0; i < size_; i++) { + VirtualString *string = strings_[i]; + if (string && string->address() == address) + return i; + } + return NOT_ID; +} + +bool StringManager::FreeString(const void *str) +{ + CriticalSection cs(critical_section_); + + size_t i = IndexByAddress(str); + if (i == NOT_ID) + return false; + + VirtualString *string = strings_[i]; + if (string->Release()) { + delete string; + strings_[i] = NULL; + } + return true; +} + +/** + * VirtualString + */ + +VirtualString::VirtualString(const STRING_ENTRY *entry_enc, HMODULE instance, uint32_t key) + : use_count_(0) +{ + STRING_ENTRY entry; + entry.Id = entry_enc->Id ^ key; + entry.OffsetToData = entry_enc->OffsetToData ^ key; + entry.Size = entry_enc->Size ^ key; + + size_ = entry.Size; + address_ = new uint8_t[size_]; + uint8_t *source = reinterpret_cast<uint8_t *>(instance) + entry.OffsetToData; + for (size_t i = 0; i < size_; i++) { + address_[i] = static_cast<uint8_t>(source[i] ^ (_rotl32(key, static_cast<int>(i)) + i)); + } +} + +VirtualString::~VirtualString() +{ + Clear(); +} + +void VirtualString::Clear() +{ + if (address_) { + volatile uint8_t *ptrSecureZeroing = address_; + while (size_--) *ptrSecureZeroing++ = 0; + delete [] address_; + address_ = NULL; + } +} + +uint8_t *VirtualString::AcquirePointer() +{ + use_count_++; + return address_; +} + +bool VirtualString::Release() +{ + use_count_--; + if (use_count_) + return false; + + Clear(); + return true; +}
\ No newline at end of file diff --git a/runtime/string_manager.h b/runtime/string_manager.h new file mode 100644 index 0000000..a35c4a4 --- /dev/null +++ b/runtime/string_manager.h @@ -0,0 +1,60 @@ +#ifndef STRING_MANAGER_H +#define STRING_MANAGER_H + +class CipherRC5; + +struct STRING_DIRECTORY { + uint32_t NumberOfEntries; + // STRING_ENTRY Entries[]; +}; + +struct STRING_ENTRY { + uint32_t Id; + uint32_t OffsetToData; + uint32_t Size; +}; + +class VirtualString +{ +public: + VirtualString(const STRING_ENTRY *entry, HMODULE instance, uint32_t key); + ~VirtualString(); + uint8_t *AcquirePointer(); + bool Release(); + uint8_t *address() const { return address_; } +private: + void Clear(); + size_t use_count_; + uint8_t *address_; + size_t size_; + + // no copy ctr or assignment op + VirtualString(const VirtualString &); + VirtualString &operator =(const VirtualString &); +}; + +class StringManager +{ +public: + StringManager(const uint8_t *data, HMODULE instance, const uint8_t *key); + ~StringManager(); + const void *DecryptString(const void *str); + bool FreeString(const void *str); +private: + STRING_DIRECTORY DecryptDirectory(const STRING_DIRECTORY *directory_enc) const; + STRING_ENTRY DecryptEntry(const STRING_ENTRY *entry_enc) const; + size_t IndexById(uint32_t id) const; + size_t IndexByAddress(const void *address) const; + const uint8_t *data_; + HMODULE instance_; + CRITICAL_SECTION critical_section_; + VirtualString **strings_; + uint32_t key_; + size_t size_; + + // no copy ctr or assignment op + StringManager(const StringManager &); + StringManager &operator =(const StringManager &); +}; + +#endif
\ No newline at end of file diff --git a/runtime/utils.cc b/runtime/utils.cc new file mode 100644 index 0000000..7d8b8de --- /dev/null +++ b/runtime/utils.cc @@ -0,0 +1,290 @@ +#include "common.h" +#include "utils.h" +#include "loader.h" + +#ifdef __unix__ +#ifdef __i386__ +__asm__(".symver memcpy,memcpy@GLIBC_2.0"); +__asm__(".symver clock_gettime,clock_gettime@LIBRT_2.12"); +#else +__asm__(".symver memcpy,memcpy@GLIBC_2.2.5"); +__asm__(".symver clock_gettime,clock_gettime@LIBRT_2.12"); +#endif +extern "C" +{ + void *__wrap_memcpy(void *dest, const void *src, size_t n) + { + return memcpy(dest, src, n); + } + + #include <sys/poll.h> + int __wrap___poll_chk (struct pollfd *fds, nfds_t nfds, int timeout, __SIZE_TYPE__ fdslen) + { + if (fdslen / sizeof (*fds) < nfds) + abort(); + + return poll (fds, nfds, timeout); + } + + #include <sys/select.h> + + + long int __wrap___fdelt_chk (long int d) + { + if (d < 0 || d >= FD_SETSIZE) + abort(); + return d / __NFDBITS; + } +} + +extern "C" size_t __fread_chk (void *destv, size_t dest_size, size_t size, size_t nmemb, FILE *f) +{ + if (size > dest_size) { + //_chk_fail(__FUNCTION__); + size = dest_size; + } + return fread(destv, size, nmemb, f); +} + +extern "C" int __isoc99_sscanf(const char *a, const char *b, va_list args) +{ + int i; + va_list ap; + va_copy(ap, args); + i = sscanf(a, b, ap); + va_end(ap); + return i; +} + +#include <setjmp.h> +extern "C" void __longjmp_chk (jmp_buf env, int val) +{ + // TODO: Glibc's __longjmp_chk additionally does some sanity checks about + // whether we're jumping a sane stack frame. + longjmp(env, val); +} + +#endif + +void ShowMessage(const VMP_CHAR *message) +{ +#ifdef __APPLE__ + char file_name[PATH_MAX]; + uint32_t name_size = sizeof(file_name); + const char *title; + if (_NSGetExecutablePath(file_name, &name_size) == 0) { + char *p = strrchr(file_name, '/'); + title = p ? p + 1 : file_name; + } else { + title = "Fatal Error"; + } + + CFStringRef title_ref = CFStringCreateWithCString(NULL, title, kCFStringEncodingMacRoman); + CFStringRef message_ref = CFStringCreateWithCString(NULL, message, kCFStringEncodingUTF8); + CFOptionFlags result; + + CFUserNotificationDisplayAlert( + 0, // no timeout + kCFUserNotificationStopAlertLevel, //change it depending message_type flags ( MB_ICONASTERISK.... etc.) + NULL, //icon url, use default, you can change it depending message_type flags + NULL, //not used + NULL, //localization of strings + title_ref, //title text + message_ref, //message text + NULL, //default "ok" text in button + NULL, //alternate button title + NULL, //other button title, null--> no other button + &result //response flags + ); + + CFRelease(title_ref); + CFRelease(message_ref); +#elif defined(__unix__) + char file_name[PATH_MAX] = {0}; + const char *title = file_name; + ssize_t len = ::readlink("/proc/self/exe", file_name, sizeof(file_name)-1); + if (len != -1) { + for (ssize_t i = 0; i < len; i++) { + if (file_name[i] == '/') + title = file_name + i + 1; + if (file_name[i] == '\'' || file_name[i] == '\\') + file_name[i] = '"'; + } + file_name[len] = '\0'; + } else { + title = "Fatal Error"; + } + std::string cmd_line = "zenity"; + cmd_line += " --error --no-markup --text='"; + cmd_line += title; + cmd_line += ": "; + char *message_buffer = strdup(message); + char *msg_ptr = message_buffer; + while (*msg_ptr) + { + if (*msg_ptr == '\'' || *msg_ptr == '\\') + *msg_ptr = '"'; + msg_ptr++; + } + cmd_line += message_buffer; + free(message_buffer); + cmd_line += "'"; + int status = system(cmd_line.c_str()); + if (status == -1 || WEXITSTATUS(status) == 127) + puts(message); +#elif defined(WIN_DRIVER) + DbgPrint("%ws\n", message); +#else + VMP_CHAR file_name[MAX_PATH + 1] = {0}; + const VMP_CHAR *title; + if (GetModuleFileNameW(reinterpret_cast<HMODULE>(FACE_IMAGE_BASE), file_name, _countof(file_name) - 1)) { + wchar_t *p = wcsrchr(file_name, L'\\'); + title = p ? p + 1 : file_name; + } else { + title = L"Fatal Error"; + } + + HMODULE ntdll = GetModuleHandleA(VMProtectDecryptStringA("ntdll.dll")); + typedef NTSTATUS(NTAPI tNtRaiseHardError)(NTSTATUS ErrorStatus, ULONG NumberOfParameters, + ULONG UnicodeStringParameterMask, PULONG_PTR Parameters, + ULONG ValidResponseOptions, + HardErrorResponse *Response); + if (tNtRaiseHardError *raise_hard_error = reinterpret_cast<tNtRaiseHardError *>(InternalGetProcAddress(ntdll, VMProtectDecryptStringA("NtRaiseHardError")))) { + UNICODE_STRING message_str; + UNICODE_STRING title_str; + + InitUnicodeString(&message_str, (PWSTR)message); + InitUnicodeString(&title_str, (PWSTR)title); + + ULONG_PTR params[4] = { + (ULONG_PTR)&message_str, + (ULONG_PTR)&title_str, + ( + (ULONG)ResponseButtonOK | IconError + ), + INFINITE + }; + + HardErrorResponse response; + raise_hard_error(STATUS_SERVICE_NOTIFICATION | HARDERROR_OVERRIDE_ERRORMODE, 4, 3, params, 0, &response); + } +#endif +} + +#ifdef VMP_GNU +#elif defined(WIN_DRIVER) +#else +void *InternalGetProcAddress(HMODULE module, const char *proc_name) +{ + // check input + if (!module || !proc_name) + return NULL; + + // check module's header + PIMAGE_DOS_HEADER dos_header = reinterpret_cast<PIMAGE_DOS_HEADER>(module); + if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) + return NULL; + + // check NT header + PIMAGE_NT_HEADERS pe_header = reinterpret_cast<PIMAGE_NT_HEADERS>(reinterpret_cast<uint8_t *>(module) + dos_header->e_lfanew); + if (pe_header->Signature != IMAGE_NT_SIGNATURE) + return NULL; + + // get the export directory + uint32_t export_adress = pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + if (!export_adress) + return NULL; + + uint32_t export_size = pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; + uint32_t address; + uint32_t ordinal_index = -1; + PIMAGE_EXPORT_DIRECTORY export_directory = reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(reinterpret_cast<uint8_t *>(module) + export_adress); + + if (proc_name <= reinterpret_cast<const char *>(0xFFFF)) { + // ordinal + ordinal_index = static_cast<uint32_t>(INT_PTR(proc_name)) - export_directory->Base; //-V221 + // index is either less than base or bigger than number of functions + if (ordinal_index >= export_directory->NumberOfFunctions) + return NULL; + // get the function offset by the ordinal + address = (reinterpret_cast<uint32_t *>(reinterpret_cast<uint8_t *>(module) + export_directory->AddressOfFunctions))[ordinal_index]; + // check for empty offset + if (!address) + return NULL; + } else { + // name of function + if (export_directory->NumberOfNames) { + // start binary search + int left_index = 0; + int right_index = export_directory->NumberOfNames - 1; + uint32_t *names = reinterpret_cast<uint32_t *>(reinterpret_cast<uint8_t *>(module) + export_directory->AddressOfNames); + while (left_index <= right_index) { + uint32_t cur_index = (left_index + right_index) >> 1; + switch (strcmp((const char *)(reinterpret_cast<uint8_t *>(module) + names[cur_index]), proc_name)) { + case 0: + ordinal_index = (reinterpret_cast<WORD *>(reinterpret_cast<uint8_t *>(module) + export_directory->AddressOfNameOrdinals))[cur_index]; + left_index = right_index + 1; + break; + case 1: + right_index = cur_index - 1; + break; + case -1: + left_index = cur_index + 1; + break; + } + } + } + // if nothing has been found + if (ordinal_index >= export_directory->NumberOfFunctions) + return NULL; + // get the function offset by the ordinal + address = (reinterpret_cast<uint32_t *>(reinterpret_cast<uint8_t *>(module) + export_directory->AddressOfFunctions))[ordinal_index]; + if (!address) + return NULL; + } + + // if it is just a pointer - return it + if (address < export_adress || address >= export_adress + export_size) + return reinterpret_cast<FARPROC>(reinterpret_cast<uint8_t *>(module) + address); + + // it is a forward + const char *name = reinterpret_cast<const char *>(reinterpret_cast<uint8_t *>(module) + address); // get a pointer to the module's name + const char *tmp = name; + const char *name_dot = NULL; + // get a pointer to the function's name + while (*tmp) { + if (*tmp == '.') { + name_dot = tmp; + break; + } + tmp++; + } + if (!name_dot) + return NULL; + + size_t name_len = name_dot - name; + if (name_len >= MAX_PATH) + return NULL; + + // copy module name + char file_name[MAX_PATH]; + size_t i; + for (i = 0; i < name_len && name[i] != 0; i++) { + file_name[i] = name[i]; + } + file_name[i] = 0; + + module = GetModuleHandleA(file_name); + if (!module) + return NULL; + + // now the function's name + // if it is not an ordinal, just forward it + if (name_dot[1] != '#') + return InternalGetProcAddress(module, name_dot + 1); + + // is is an ordinal + int ordinal = atoi(name_dot + 2); + return InternalGetProcAddress(module, LPCSTR(INT_PTR(ordinal))); +} +#endif
\ No newline at end of file diff --git a/runtime/utils.h b/runtime/utils.h new file mode 100644 index 0000000..66944e7 --- /dev/null +++ b/runtime/utils.h @@ -0,0 +1,23 @@ +#ifndef UTILS_H +#define UTILS_H + +void ShowMessage(const VMP_CHAR *message); + +#ifdef VMP_GNU +#elif defined(WIN_DRIVER) +HMODULE GetModuleHandleA(const char *name); +#else +void *InternalGetProcAddress(HMODULE module, const char *proc_name); + +__forceinline void InitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString) +{ + if (SourceString) + DestinationString->MaximumLength = (DestinationString->Length = (USHORT)(wcslen(SourceString) * sizeof(WCHAR))) + sizeof(UNICODE_NULL); + else + DestinationString->MaximumLength = DestinationString->Length = 0; + + DestinationString->Buffer = (PWCH)SourceString; +} +#endif + +#endif
\ No newline at end of file |