aboutsummaryrefslogtreecommitdiff
path: root/runtime/VMProtect.Runtime/Loader.cs
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/VMProtect.Runtime/Loader.cs')
-rw-r--r--runtime/VMProtect.Runtime/Loader.cs703
1 files changed, 703 insertions, 0 deletions
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