public void TestPatternScan() { // Allocate memory in the host process const int testRegionSize = 32; var testRegionAddress = _memoryModule.AllocateMemory(_hostProcessName, testRegionSize); // Write a test array of bytes into memory var testArray = new byte[] { 0xFF, 0x01, 0x5A, 0xFF, 0x22, 0x00, 0x1A, 0xAA, 0xFF, 0xFF, 0xFF }; _memoryModule.WriteMemory(_hostProcessName, testRegionAddress, testArray); // Scan the host process for test array pattern const string testArrayPattern = "FF 01 ?? FF 22 00 ?? AA FF ?? FF"; var result = _memoryModule.PatternScan(_hostProcessName, IntPtr.Zero, testArrayPattern); Assert.Contains(testRegionAddress, result); // Free the memory that was allocated _memoryModule.FreeMemory(_hostProcessName, testRegionAddress); }
internal bool Erase(Process process, string dllPath) { // Get the id of the process var processId = process.Id; // Get the name of the dll var dllName = Path.GetFileName(dllPath); // Get an instance of the dll in the process var module = process.Modules.Cast <ProcessModule>().SingleOrDefault(m => string.Equals(m.ModuleName, dllName, StringComparison.OrdinalIgnoreCase)); if (module is null) { throw new ArgumentException($"There is no module named {dllName} loaded in the process"); } // Get the base address of the dll var dllBaseAddress = module.BaseAddress; // Open a handle to the process var processHandle = process.SafeHandle; // Get the information about the header region of the dll var memoryInformationSize = Marshal.SizeOf(typeof(Native.MemoryBasicInformation)); if (!Native.VirtualQueryEx(processHandle, dllBaseAddress, out var memoryInformation, memoryInformationSize)) { ExceptionHandler.ThrowWin32Exception("Failed to query the memory of the process"); } // Create a buffer to write over the header region with var buffer = new byte[(int)memoryInformation.RegionSize]; // Write over the header region with the buffer try { _memoryModule.WriteMemory(processId, dllBaseAddress, buffer); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to write over the header region"); } // Close the handle opened to the process processHandle?.Close(); return(true); }
public void TestReadMemory() { // Allocate memory in the host process const int testRegionSize = 32; var testRegionAddress = _memoryModule.AllocateMemory(_hostProcessName, testRegionSize); // Write a test array of bytes into memory var testArray = new byte[] { 0xFF, 0x01, 0x5A, 0xFF, 0x22, 0x00 }; _memoryModule.WriteMemory(_hostProcessName, testRegionAddress, testArray); // Read the test array of bytes from memory var readTestArray = _memoryModule.ReadMemory(_hostProcessName, testRegionAddress, testArray.Length); Assert.True(testArray.SequenceEqual(readTestArray)); // Free the memory that was allocated _memoryModule.FreeMemory(_hostProcessName, testRegionAddress); }
internal bool Inject(Process process, string dllPath) { // Ensure the process has kernel32.dll loaded if (Native.LoadLibrary("kernel32.dll") is null) { ExceptionHandler.ThrowWin32Exception("Failed to load kernel32.dll into the process"); } // Get the id of the process var processId = process.Id; // Get the address of the LoadLibraryW method from kernel32.dll var loadLibraryAddress = Native.GetProcAddress(Native.GetModuleHandle("kernel32.dll"), "LoadLibraryW"); if (loadLibraryAddress == IntPtr.Zero) { ExceptionHandler.ThrowWin32Exception("Failed to find the address of the LoadLibraryW method in kernel32.dll"); } // Allocate memory for the dll path in the process var dllPathSize = dllPath.Length; var dllPathAddress = IntPtr.Zero; try { dllPathAddress = _memoryModule.AllocateMemory(processId, dllPathSize); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to allocate memory for the dll path in the process"); } // Write the dll path into the process var dllPathBytes = Encoding.Unicode.GetBytes(dllPath + "\0"); try { _memoryModule.WriteMemory(processId, dllPathAddress, dllPathBytes); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to write the dll path into the memory of the process"); } // Open a handle to the process var processHandle = process.SafeHandle; // Create a remote thread to call load library in the process Native.RtlCreateUserThread(processHandle, IntPtr.Zero, false, 0, IntPtr.Zero, IntPtr.Zero, loadLibraryAddress, dllPathAddress, out var remoteThreadHandle, 0); if (remoteThreadHandle is null) { ExceptionHandler.ThrowWin32Exception("Failed to create a remote thread to call load library in the process"); } // Wait for the remote thread to finish its task Native.WaitForSingleObject(remoteThreadHandle, int.MaxValue); // Free the memory previously allocated for the dll path try { _memoryModule.FreeMemory(processId, dllPathAddress); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to free the memory allocated for the dll path in the process"); } // Close the handle opened to the process processHandle.Close(); // Close the handle opened to the remote thread remoteThreadHandle.Close(); return(true); }
private void CallEntryPoint(IntPtr baseAddress, IntPtr entryPoint) { // Get the id of the process var processId = _process.Id; // Open a handle to the process var processHandle = _process.SafeHandle; // Determine if the process is running under WOW64 Native.IsWow64Process(processHandle, out var isWow64); // Create shellcode to call the entry of the dll in the process var shellcodeBytes = isWow64 ? Shellcode.CallDllMainx86(baseAddress, entryPoint) : Shellcode.CallDllMainx64(baseAddress, entryPoint); // Allocate memory for the shellcode in the process var shellcodeSize = shellcodeBytes.Length; var shellcodeAddress = IntPtr.Zero; try { shellcodeAddress = _memoryModule.AllocateMemory(processId, shellcodeSize); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to allocate memory for the shellcode in the process"); } // Write the shellcode into the memory of the process try { _memoryModule.WriteMemory(processId, shellcodeAddress, shellcodeBytes); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to write the shellcode into the memory of the process"); } // Create a remote thread to call the entry point in the process Native.RtlCreateUserThread(processHandle, IntPtr.Zero, false, 0, IntPtr.Zero, IntPtr.Zero, shellcodeAddress, IntPtr.Zero, out var remoteThreadHandle, 0); if (remoteThreadHandle is null) { ExceptionHandler.ThrowWin32Exception("Failed to create a remote thread to call the entry point in the process"); } // Wait for the remote thread to finish its task Native.WaitForSingleObject(remoteThreadHandle, int.MaxValue); // Free the memory previously allocated for the shellcode try { _memoryModule.FreeMemory(processId, shellcodeAddress); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to free the memory allocated for the shellcode in the process"); } // Close the handle opened to the process processHandle?.Close(); // Close the handle opened to the remote thread remoteThreadHandle?.Close(); }
internal bool Unlink(Process process, string dllPath) { // Get the id of the process var processId = process.Id; // Get the size of the process basic information structure var pbiSize = Marshal.SizeOf(typeof(Native.ProcessBasicInformation)); // Allocate memory for a buffer to store the process basic information var pbiBuffer = Marshal.AllocHGlobal(pbiSize); // Open a handle to the process var processHandle = process.SafeHandle; // Query the process and store the process basic information in the buffer Native.NtQueryInformationProcess(processHandle, 0, pbiBuffer, pbiSize, 0); // Read the process basic information from the buffer var pbi = Tools.PointerToStructure <Native.ProcessBasicInformation>(pbiBuffer); if (pbi.Equals(default(Native.ProcessBasicInformation))) { ExceptionHandler.ThrowWin32Exception("Failed to query the memory of the process"); } // Read the process environment block from the process var peb = default(Native.Peb); try { peb = _memoryModule.ReadMemory <Native.Peb>(processId, pbi.PebBaseAddress); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to read the process environment block of the process"); } // Read the process environment block loader data from the process var pebLoaderData = default(Native.PebLdrData); try { pebLoaderData = _memoryModule.ReadMemory <Native.PebLdrData>(processId, peb.Ldr); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to read the process environment block loader data of the process"); } // Get the address of the first dll entry in the processes module list var currentEntry = pebLoaderData.InLoadOrderModuleList.Flink; // Get the address of the last dll entry in the processes module list var lastEntry = pebLoaderData.InLoadOrderModuleList.Blink; while (true) { // Read the information about the current dll entry var dllEntry = default(Native.LdrDataTableEntry); try { dllEntry = _memoryModule.ReadMemory <Native.LdrDataTableEntry>(processId, currentEntry); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to read the information of a dll entry"); } // Read the full dll name of the current dll entry var dllEntryNameBytes = new byte[0]; try { dllEntryNameBytes = _memoryModule.ReadMemory(processId, dllEntry.FullDllName.Buffer, dllEntry.FullDllName.Length); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to read the dll path of a dll entry"); } var ldrEntryName = Encoding.UTF8.GetString(dllEntryNameBytes).Replace("\0", ""); if (string.Equals(dllPath, ldrEntryName, StringComparison.OrdinalIgnoreCase)) { // Unlink the dll from the necessary links UnlinkModule(processId, dllEntry.InLoadOrderLinks); UnlinkModule(processId, dllEntry.InMemoryOrderLinks); UnlinkModule(processId, dllEntry.InInitOrderLinks); // Create a buffer to write over the base dll name buffer with var baseDllNameBuffer = new byte[dllEntry.BaseDllName.MaxLength]; // Create a buffer to write over the full dll name buffer with var fullDllNameBuffer = new byte[dllEntry.FullDllName.MaxLength]; // Create a buffer to write over the entry with var ldrDataTableEntrySize = Marshal.SizeOf(typeof(Native.LdrDataTableEntry)); var currentEntryBuffer = new byte[ldrDataTableEntrySize]; // Write over the base dll name buffer with the new buffer try { _memoryModule.WriteMemory(processId, dllEntry.BaseDllName.Buffer, baseDllNameBuffer); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to write over the dll name buffer"); } // Write over the full dll name buffer with the new buffer try { _memoryModule.WriteMemory(processId, dllEntry.FullDllName.Buffer, fullDllNameBuffer); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to write over the dll path buffer"); } // Write over the dll entry with the new buffer try { _memoryModule.WriteMemory(processId, currentEntry, currentEntryBuffer); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to write over the dll entry"); } break; } if (currentEntry == lastEntry) { // The dll wasn't found in the process environment block var dllName = Path.GetFileName(dllPath); throw new ArgumentException($"No entry with the name {dllName} was found in the process environment block"); } // Jump to the next entry currentEntry = dllEntry.InLoadOrderLinks.Flink; } // Free the memory previously allocated for the buffer Marshal.FreeHGlobal(pbiBuffer); // Close the handle opened to the process processHandle?.Close(); return(true); }
internal bool Inject(Process process, string dllPath) { // Ensure the process has kernel32.dll loaded if (Native.LoadLibrary("kernel32.dll") is null) { ExceptionHandler.ThrowWin32Exception("Failed to load kernel32.dll into the process"); } // Get the id of the process var processId = process.Id; // Get the address of the LoadLibraryW method from kernel32.dll var loadLibraryAddress = Native.GetProcAddress(Native.GetModuleHandle("kernel32.dll"), "LoadLibraryW"); if (loadLibraryAddress == IntPtr.Zero) { ExceptionHandler.ThrowWin32Exception("Failed to find the address of the LoadLibraryW method in kernel32.dll"); } // Allocate memory for the dll path in the process var dllPathSize = dllPath.Length; var dllPathAddress = IntPtr.Zero; try { dllPathAddress = _memoryModule.AllocateMemory(processId, dllPathSize); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to allocate memory for the dll path in the process"); } // Write the dll path into the process var dllPathBytes = Encoding.Unicode.GetBytes(dllPath + "\0"); try { _memoryModule.WriteMemory(processId, dllPathAddress, dllPathBytes); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to write the dll path into the memory of the process"); } foreach (var thread in process.Threads.Cast <ProcessThread>()) { // Open a handle to the thread var threadHandle = Native.OpenThread(Native.ThreadAccess.SetContext, false, thread.Id); if (threadHandle is null) { ExceptionHandler.ThrowWin32Exception("Failed to open a handle to a thread in the process"); } // Add a user-mode APC to the APC queue of the thread if (!Native.QueueUserAPC(loadLibraryAddress, threadHandle, dllPathAddress)) { ExceptionHandler.ThrowWin32Exception("Failed to queue a user-mode apc to the apc queue of a thread in the process"); } // Close the handle opened to the thread threadHandle?.Close(); } // Free the memory previously allocated for the dll path try { _memoryModule.FreeMemory(processId, dllPathAddress); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to free the memory allocated for the dll path in the process"); } return(true); }
internal bool Inject(Process process, string dllPath) { // Ensure the process has kernel32.dll loaded if (Native.LoadLibrary("kernel32.dll") is null) { ExceptionHandler.ThrowWin32Exception("Failed to load kernel32.dll into the process"); } // Get the id of the process var processId = process.Id; // Get the address of the LoadLibraryW method from kernel32.dll var loadLibraryAddress = Native.GetProcAddress(Native.GetModuleHandle("kernel32.dll"), "LoadLibraryW"); if (loadLibraryAddress == IntPtr.Zero) { ExceptionHandler.ThrowWin32Exception("Failed to find the address of the LoadLibraryW method in kernel32.dll"); } // Allocate memory for the dll path in the process var dllPathSize = dllPath.Length; var dllPathAddress = IntPtr.Zero; try { dllPathAddress = _memoryModule.AllocateMemory(processId, dllPathSize); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to allocate memory for the dll path in the process"); } // Write the dll path into the process var dllPathBytes = Encoding.Unicode.GetBytes(dllPath + "\0"); try { _memoryModule.WriteMemory(processId, dllPathAddress, dllPathBytes); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to write the dll path into the memory of the process"); } // Open a handle to the process var processHandle = process.SafeHandle; // Determine if the process is running under WOW64 Native.IsWow64Process(processHandle, out var isWow64); // Allocate memory for the shellcode in the process var shellcodeSize = isWow64 ? 22 : 87; var shellcodeAddress = IntPtr.Zero; try { shellcodeAddress = _memoryModule.AllocateMemory(processId, shellcodeSize); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to allocate memory for the shellcode in the process"); } // Get the id of the first thread in the process var threadId = process.Threads[0].Id; // Open a handle to the thread var threadHandle = Native.OpenThread(Native.ThreadAccess.AllAccess, false, threadId); if (threadHandle is null) { ExceptionHandler.ThrowWin32Exception("Failed to open a handle to the first thread in the process"); } // Suspend the thread if (Native.SuspendThread(threadHandle) == -1) { ExceptionHandler.ThrowWin32Exception("Failed to suspend the first thread in the process"); } // If the process is x86 if (isWow64) { var threadContext = new Native.Context { Flags = Native.ContextFlags.ContextControl }; // Store the thread context structure in a buffer var threadContextBuffer = Tools.StructureToPointer(threadContext); // Get the context of the thread and save it in the buffer if (!Native.GetThreadContext(threadHandle, threadContextBuffer)) { ExceptionHandler.ThrowWin32Exception("Failed to get the context of the first thread in the process"); } // Read the new thread context structure from the buffer threadContext = Tools.PointerToStructure <Native.Context>(threadContextBuffer); // Save the instruction pointer var instructionPointer = threadContext.Eip; // Write the shellcode into the memory of the process var shellcodeBytes = Shellcode.CallLoadLibraryx86(instructionPointer, dllPathAddress, loadLibraryAddress); try { _memoryModule.WriteMemory(processId, shellcodeAddress, shellcodeBytes); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to write the shellcode into the memory of the process"); } // Change the instruction pointer to the shellcode address threadContext.Eip = shellcodeAddress; // Store the thread context structure in a buffer threadContextBuffer = Tools.StructureToPointer(threadContext); // Set the context of the thread with the new context if (!Native.SetThreadContext(threadHandle, threadContextBuffer)) { ExceptionHandler.ThrowWin32Exception("Failed to set the context of the first thread in the process"); } } // If the process is x64 else { var threadContext = new Native.Context64 { Flags = Native.ContextFlags.ContextControl }; // Store the thread context structure in a buffer var threadContextBuffer = Tools.StructureToPointer(threadContext); // Get the context of the thread and save it in the buffer if (!Native.GetThreadContext(threadHandle, threadContextBuffer)) { ExceptionHandler.ThrowWin32Exception("Failed to get the context of the first thread in the process"); } // Read the new thread context structure from the buffer threadContext = Tools.PointerToStructure <Native.Context64>(threadContextBuffer); // Save the instruction pointer var instructionPointer = threadContext.Rip; // Write the shellcode into the memory of the process var shellcodeBytes = Shellcode.CallLoadLibraryx64(instructionPointer, dllPathAddress, loadLibraryAddress); try { _memoryModule.WriteMemory(processId, shellcodeAddress, shellcodeBytes); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to write the shellcode into the memory of the process"); } // Change the instruction pointer to the shellcode address threadContext.Rip = shellcodeAddress; // Store the thread context structure in a buffer threadContextBuffer = Tools.StructureToPointer(threadContext); // Set the context of the thread with the new context if (!Native.SetThreadContext(threadHandle, threadContextBuffer)) { ExceptionHandler.ThrowWin32Exception("Failed to set the context of the first thread in the process"); } } // Resume the suspended thread if (Native.ResumeThread(threadHandle) == -1) { ExceptionHandler.ThrowWin32Exception("Failed to resume the first thread in the process"); } // Open a handle to the main window of the process var windowHandle = new SafeWindowHandle(process.MainWindowHandle); // Switch to the process to load the dll Native.SwitchToThisWindow(windowHandle, true); // Buffer the execution by 10 milliseconds to avoid freeing memory before it has been referenced Tools.AsyncWait(10); // Free the memory previously allocated for the dll path try { _memoryModule.FreeMemory(processId, dllPathAddress); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to free the memory allocated for the dll path in the process"); } // Free the memory previously allocated for the shellcode try { _memoryModule.FreeMemory(processId, shellcodeAddress); } catch (Win32Exception) { ExceptionHandler.ThrowWin32Exception("Failed to free the memory allocated for the shellcode in the process"); } // Close the handle opened to the process processHandle?.Close(); // Close the handle opened to the thread threadHandle?.Close(); return(true); }