aboutsummaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/CFGregorianDateCreate.hpp303
-rw-r--r--runtime/VMProtect.Runtime/Core.cs526
-rw-r--r--runtime/VMProtect.Runtime/CpuId.cs87
-rw-r--r--runtime/VMProtect.Runtime/Crypto.cs195
-rw-r--r--runtime/VMProtect.Runtime/Faces.cs170
-rw-r--r--runtime/VMProtect.Runtime/HardwareID.cs266
-rw-r--r--runtime/VMProtect.Runtime/LicensingManager.cs664
-rw-r--r--runtime/VMProtect.Runtime/Loader.cs703
-rw-r--r--runtime/VMProtect.Runtime/LzmaDecoder.cs651
-rw-r--r--runtime/VMProtect.Runtime/Numerics/BigInteger.cs2012
-rw-r--r--runtime/VMProtect.Runtime/Numerics/BigIntegerBuilder.cs1529
-rw-r--r--runtime/VMProtect.Runtime/Numerics/NumericHelpers.cs425
-rw-r--r--runtime/VMProtect.Runtime/Properties/AssemblyInfo.cs35
-rw-r--r--runtime/VMProtect.Runtime/StringManager.cs65
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/LicensingManagerTests.cs122
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/LoaderTests.cs47
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/MsilToVmTestCompiler.cs100
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/Properties/AssemblyInfo.cs35
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/ElementedTypeHelper.cs172
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/MyBuffer.cs569
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/MyBufferReader.cs563
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/MyCollection.cs361
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/SdMetadataTokens.cs288
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/SdTemplateStuff.cs180
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/SimpleTypeHelper.cs26
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/StringDecryptor.cs648
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/TypeCompatibility.cs54
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VariantBase.cs2621
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VariantFactory.cs165
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VmExecutor.cs7505
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VmInstrCodesDb.cs899
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VmMethodHeader.cs42
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VmPosParser.cs96
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/RefVm/VmStreamWrapper.cs116
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/UnitTest1.cs110
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/UnitTestCombine.cs1715
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/UnitTestProject.csproj159
-rw-r--r--runtime/VMProtect.Runtime/Tests/UnitTestProject/UnitTestProject.csproj.bak133
-rw-r--r--runtime/VMProtect.Runtime/VMProtect.Netcore.csproj65
-rw-r--r--runtime/VMProtect.Runtime/VMProtect.Runtime.csproj93
-rw-r--r--runtime/VMProtect.Runtime/VirtualMachine.cs4285
-rw-r--r--runtime/VMProtect.Runtime/Win32.cs825
-rw-r--r--runtime/common.h291
-rw-r--r--runtime/core.cc1365
-rw-r--r--runtime/core.h149
-rw-r--r--runtime/crypto.cc1086
-rw-r--r--runtime/crypto.h388
-rw-r--r--runtime/file_manager.cc1189
-rw-r--r--runtime/file_manager.h348
-rw-r--r--runtime/hook_manager.cc738
-rw-r--r--runtime/hook_manager.h40
-rw-r--r--runtime/hwid.cc688
-rw-r--r--runtime/hwid.h45
-rw-r--r--runtime/licensing_manager.cc1135
-rw-r--r--runtime/licensing_manager.h100
-rw-r--r--runtime/lin_runtime.mak32
-rw-r--r--runtime/lin_runtime32.mak3
-rw-r--r--runtime/lin_runtime64.mak4
-rw-r--r--runtime/loader.cc2946
-rw-r--r--runtime/loader.h570
-rw-r--r--runtime/mac_runtime.mak31
-rw-r--r--runtime/mac_runtime32.mak3
-rw-r--r--runtime/mac_runtime64.mak3
-rw-r--r--runtime/objects.cc59
-rw-r--r--runtime/objects.h78
-rw-r--r--runtime/precommon.h146
-rw-r--r--runtime/precompiled.cc1
-rw-r--r--runtime/precompiled.h133
-rw-r--r--runtime/registry_manager.cc1390
-rw-r--r--runtime/registry_manager.h299
-rw-r--r--runtime/resource_manager.cc1022
-rw-r--r--runtime/resource_manager.h148
-rw-r--r--runtime/runtime.def33
-rw-r--r--runtime/string_manager.cc184
-rw-r--r--runtime/string_manager.h60
-rw-r--r--runtime/utils.cc290
-rw-r--r--runtime/utils.h23
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 &registry_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 &registry_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 *>(&timestamp));
+
+ // 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, &copy_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