internal void CallFunction(CallingConvention callingConvention, IntPtr functionAddress, params ulong[] parameters) { // Write the shellcode used to call the function into the remote process var shellcode = _assembler.AssembleFunctionCall(callingConvention, functionAddress, IntPtr.Zero, parameters); var shellcodeBuffer = _memoryManager.AllocateVirtualMemory(shellcode.Length); _memoryManager.WriteVirtualMemory(shellcodeBuffer, shellcode); // Create a thread to call the shellcode in the remote process var ntStatus = RtlCreateUserThread(Process.SafeHandle, IntPtr.Zero, false, 0, IntPtr.Zero, IntPtr.Zero, shellcodeBuffer, IntPtr.Zero, out var threadHandle, IntPtr.Zero); if (ntStatus != NtStatus.Success) { ExceptionHandler.ThrowWin32Exception("Failed to create a thread in the remote process"); } WaitForSingleObject(threadHandle, int.MaxValue); threadHandle.Dispose(); _memoryManager.FreeVirtualMemory(shellcodeBuffer); }
internal void CallFunction(IntPtr functionAddress, ulong[] parameters, CallingConvention callingConvention = CallingConvention.StdCall) { // Write the shellcode used to call the function into the remote process var shellcode = callingConvention == CallingConvention.FastCall ? _assembler.AssembleFastCallFunctionCall(functionAddress, IntPtr.Zero, parameters.ToArray()) : _assembler.AssembleStandardFunctionCall(functionAddress, IntPtr.Zero, parameters.ToArray()); var shellcodeBuffer = _memoryManager.AllocateVirtualMemory(shellcode.Length); _memoryManager.WriteVirtualMemory(shellcodeBuffer, shellcode); // Create a thread in the remote process to call the shellcode var ntStatus = PInvoke.RtlCreateUserThread(Process.SafeHandle, IntPtr.Zero, false, 0, IntPtr.Zero, IntPtr.Zero, shellcodeBuffer, IntPtr.Zero, out var threadHandle, out _); if (ntStatus != Enumerations.NtStatus.Success) { ExceptionHandler.ThrowWin32Exception("Failed to create a thread in the remote process"); } PInvoke.WaitForSingleObject(threadHandle, int.MaxValue); threadHandle.Dispose(); _memoryManager.FreeVirtualMemory(shellcodeBuffer); }
internal IntPtr InitialiseDllPath() { // Write the DLL path into the remote process var dllPathAddress = MemoryManager.AllocateVirtualMemory(ProcessManager.Process.SafeHandle, IntPtr.Zero, DllPath.Length, MemoryProtectionType.ReadWrite); MemoryManager.WriteVirtualMemory(ProcessManager.Process.SafeHandle, dllPathAddress, Encoding.Unicode.GetBytes(DllPath)); // Write a UnicodeString representing the DLL path into the remote process IntPtr dllPathUnicodeStringAddress; if (ProcessManager.IsWow64) { var dllPathUnicodeString = new UnicodeString32(DllPath, dllPathAddress); dllPathUnicodeStringAddress = MemoryManager.AllocateVirtualMemory(ProcessManager.Process.SafeHandle, IntPtr.Zero, Marshal.SizeOf <UnicodeString32>(), MemoryProtectionType.ReadWrite); MemoryManager.WriteVirtualMemory(ProcessManager.Process.SafeHandle, dllPathUnicodeStringAddress, dllPathUnicodeString); } else { var dllPathUnicodeString = new UnicodeString64(DllPath, dllPathAddress); dllPathUnicodeStringAddress = MemoryManager.AllocateVirtualMemory(ProcessManager.Process.SafeHandle, IntPtr.Zero, Marshal.SizeOf <UnicodeString64>(), MemoryProtectionType.ReadWrite); MemoryManager.WriteVirtualMemory(ProcessManager.Process.SafeHandle, dllPathUnicodeStringAddress, dllPathUnicodeString); } return(dllPathUnicodeStringAddress); }
internal TStructure CallFunction <TStructure>(CallingConvention callingConvention, IntPtr functionAddress, params long[] parameters) where TStructure : struct { var returnAddress = MemoryManager.AllocateVirtualMemory(Marshal.SizeOf <TStructure>(), MemoryProtectionType.ReadWrite); CallFunctionInternal(new FunctionCall(functionAddress, callingConvention, parameters, returnAddress)); try { return(MemoryManager.ReadVirtualMemory <TStructure>(returnAddress)); } finally { MemoryManager.FreeVirtualMemory(returnAddress); } }
internal TStructure CallFunction <TStructure>(IntPtr functionAddress, params ulong[] parameters) where TStructure : struct { // Allocate a buffer in the remote process to store the returned value of the function var returnBuffer = _memoryManager.AllocateVirtualMemory <TStructure>(); // Write the shellcode used to call the function into the remote process var shellcode = _assembler.AssembleFunctionCall(functionAddress, returnBuffer, parameters); var shellcodeBuffer = _memoryManager.AllocateVirtualMemory(shellcode.Length); _memoryManager.WriteVirtualMemory(shellcodeBuffer, shellcode); // Create a thread in the remote process to call the shellcode SafeThreadHandle threadHandle; var ntStatus = _windowsVersion == WindowsVersion.Windows7 ? PInvoke.NtCreateThreadEx(out threadHandle, Enumerations.ThreadAccessMask.AllAccess, IntPtr.Zero, Process.SafeHandle, shellcodeBuffer, IntPtr.Zero, Enumerations.ThreadCreationType.HideFromDebugger, 0, 0, 0, IntPtr.Zero) : PInvoke.RtlCreateUserThread(Process.SafeHandle, IntPtr.Zero, false, 0, IntPtr.Zero, IntPtr.Zero, shellcodeBuffer, IntPtr.Zero, out threadHandle, out _); if (ntStatus != Enumerations.NtStatus.Success) { ExceptionHandler.ThrowWin32Exception("Failed to create a thread in the remote process"); } PInvoke.WaitForSingleObject(threadHandle, int.MaxValue); threadHandle.Dispose(); _memoryManager.FreeVirtualMemory(shellcodeBuffer); try { // Read the returned value of the function from the buffer return(_memoryManager.ReadVirtualMemory <TStructure>(returnBuffer)); } finally { _memoryManager.FreeVirtualMemory(returnBuffer); } }
internal override void Inject() { // Write the DLL path into the remote process var dllPathUnicodeStringAddress = InitialiseDllPath(); // Create a thread to call LdrLoadDll in the remote process var ldrLoadDllAddress = ProcessManager.GetFunctionAddress("ntdll.dll", "LdrLoadDll"); var moduleHandleAddress = MemoryManager.AllocateVirtualMemory(ProcessManager.Process.SafeHandle, IntPtr.Zero, IntPtr.Size, MemoryProtectionType.ReadWrite); var ntStatus = ProcessManager.CallFunction <int>(CallingConvention.StdCall, ldrLoadDllAddress, 0, 0, (long)dllPathUnicodeStringAddress, (long)moduleHandleAddress); if ((NtStatus)ntStatus != NtStatus.Success) { throw new RemoteFunctionCallException("Failed to call LdrLoadDll", (NtStatus)ntStatus); } // Ensure the DLL is loaded before freeing any memory while (ProcessManager.Modules.TrueForAll(module => module.FilePath != DllPath)) { ProcessManager.Refresh(); } var dllPathAddress = ProcessManager.IsWow64 ? (IntPtr)MemoryManager.ReadVirtualMemory <UnicodeString32>(ProcessManager.Process.SafeHandle, dllPathUnicodeStringAddress).Buffer : (IntPtr)MemoryManager.ReadVirtualMemory <UnicodeString64>(ProcessManager.Process.SafeHandle, dllPathUnicodeStringAddress).Buffer; MemoryManager.FreeVirtualMemory(ProcessManager.Process.SafeHandle, dllPathAddress); MemoryManager.FreeVirtualMemory(ProcessManager.Process.SafeHandle, dllPathUnicodeStringAddress); // Read the address of the DLL that was loaded in the remote process DllBaseAddress = MemoryManager.ReadVirtualMemory <IntPtr>(ProcessManager.Process.SafeHandle, moduleHandleAddress); MemoryManager.FreeVirtualMemory(ProcessManager.Process.SafeHandle, moduleHandleAddress); if (InjectionFlags.HasFlag(InjectionFlags.HideDllFromPeb)) { // Hide the DLL from the PEB of the remote process HideDllFromPeb(); } if (InjectionFlags.HasFlag(InjectionFlags.RandomiseDllHeaders)) { // Randomise the DLL headers RandomiseDllHeaders(DllBaseAddress); } }
internal override void Inject() { // Store the DLL in the local process _localDllAddress = Marshal.AllocHGlobal(DllBytes.Length); Marshal.Copy(DllBytes, 0, _localDllAddress, DllBytes.Length); // Allocate memory for the DLL in the remote process try { DllBaseAddress = MemoryManager.AllocateVirtualMemory(ProcessManager.Process.SafeHandle, (IntPtr)PeImage.PeHeaders.PEHeader.ImageBase, PeImage.PeHeaders.PEHeader.SizeOfImage, MemoryProtectionType.ReadWrite); } catch (PInvokeException) { DllBaseAddress = MemoryManager.AllocateVirtualMemory(ProcessManager.Process.SafeHandle, IntPtr.Zero, PeImage.PeHeaders.PEHeader.SizeOfImage, MemoryProtectionType.ReadWrite); } // Build the import table of the DLL in the local process BuildImportTable(); // Relocate the DLL in the local process RelocateImage(); // Map the sections of the DLL into the remote process MapSections(); // Map the headers of the DLL into the remote process MapHeaders(); // Enable exception handling within the DLL EnableExceptionHandling(); // Call the init routines CallInitRoutines(); }
internal override void Inject() { // Write the DLL path into the remote process var dllPathUnicodeStringAddress = InitialiseDllPath(); // Write the shellcode used to call LdrLoadDll into the remote process var ldrLoadDllAddress = ProcessManager.GetFunctionAddress("ntdll.dll", "LdrLoadDll"); var moduleHandleAddress = MemoryManager.AllocateVirtualMemory(ProcessManager.Process.SafeHandle, IntPtr.Zero, IntPtr.Size, MemoryProtectionType.ReadWrite); var shellcodeReturnAddress = MemoryManager.AllocateVirtualMemory(ProcessManager.Process.SafeHandle, IntPtr.Zero, sizeof(int), MemoryProtectionType.ReadWrite); var shellcode = Assembler.AssembleThreadFunctionCall(new FunctionCall(ProcessManager.IsWow64, ldrLoadDllAddress, CallingConvention.StdCall, new[] { 0, 0, (long)dllPathUnicodeStringAddress, (long)moduleHandleAddress }, shellcodeReturnAddress)); var shellcodeAddress = MemoryManager.AllocateVirtualMemory(ProcessManager.Process.SafeHandle, IntPtr.Zero, shellcode.Length, MemoryProtectionType.ReadWrite); MemoryManager.WriteVirtualMemory(ProcessManager.Process.SafeHandle, shellcodeAddress, shellcode); MemoryManager.ProtectVirtualMemory(ProcessManager.Process.SafeHandle, shellcodeAddress, shellcode.Length, MemoryProtectionType.ExecuteRead); // Open a handle to the first thread in the remote process var firstThreadHandle = Kernel32.OpenThread(Constants.ThreadAllAccess, false, ProcessManager.Process.Threads[0].Id); if (firstThreadHandle is null) { throw new PInvokeException("Failed to call OpenThread"); } if (ProcessManager.IsWow64) { // Suspend the thread if (Kernel32.Wow64SuspendThread(firstThreadHandle) == -1) { throw new PInvokeException("Failed to call Wow64SuspendThread"); } // Get the context of the thread var threadContext = new Context32 { ContextFlags = ContextFlags.Control }; var threadContextBuffer = Marshal.AllocHGlobal(Marshal.SizeOf <Context32>()); Marshal.StructureToPtr(threadContext, threadContextBuffer, false); if (!Kernel32.Wow64GetThreadContext(firstThreadHandle, threadContextBuffer)) { throw new PInvokeException("Failed to call Wow64GetThreadContext"); } threadContext = Marshal.PtrToStructure <Context32>(threadContextBuffer); // Write the original instruction pointer of the thread into the top of its stack threadContext.Esp -= sizeof(int); MemoryManager.WriteVirtualMemory(ProcessManager.Process.SafeHandle, (IntPtr)threadContext.Esp, threadContext.Eip); // Overwrite the instruction pointer of the thread with the address of the shellcode threadContext.Eip = (int)shellcodeAddress; Marshal.StructureToPtr(threadContext, threadContextBuffer, false); // Update the context of the thread if (!Kernel32.Wow64SetThreadContext(firstThreadHandle, threadContextBuffer)) { throw new PInvokeException("Failed to call Wow64SetThreadContext"); } Marshal.FreeHGlobal(threadContextBuffer); } else { // Suspend the thread if (Kernel32.SuspendThread(firstThreadHandle) == -1) { throw new PInvokeException("Failed to call SuspendThread"); } // Get the context of the thread var threadContext = new Context64 { ContextFlags = ContextFlags.Control }; var threadContextBuffer = Marshal.AllocHGlobal(Marshal.SizeOf <Context64>()); Marshal.StructureToPtr(threadContext, threadContextBuffer, false); if (!Kernel32.GetThreadContext(firstThreadHandle, threadContextBuffer)) { throw new PInvokeException("Failed to call GetThreadContext"); } threadContext = Marshal.PtrToStructure <Context64>(threadContextBuffer); // Write the original instruction pointer of the thread into the top of its stack threadContext.Rsp -= sizeof(long); MemoryManager.WriteVirtualMemory(ProcessManager.Process.SafeHandle, (IntPtr)threadContext.Rsp, threadContext.Rip); // Overwrite the instruction pointer of the thread with the address of the shellcode threadContext.Rip = (long)shellcodeAddress; Marshal.StructureToPtr(threadContext, threadContextBuffer, false); // Update the context of the thread if (!Kernel32.SetThreadContext(firstThreadHandle, threadContextBuffer)) { throw new PInvokeException("Failed to call SetThreadContext"); } Marshal.FreeHGlobal(threadContextBuffer); } // Send a message to the thread to ensure it executes the shellcode User32.PostThreadMessage(ProcessManager.Process.Threads[0].Id, MessageType.Null, IntPtr.Zero, IntPtr.Zero); // Resume the thread if (Kernel32.ResumeThread(firstThreadHandle) == -1) { throw new PInvokeException("Failed to call ResumeThread"); } firstThreadHandle.Dispose(); var shellcodeReturn = MemoryManager.ReadVirtualMemory <int>(ProcessManager.Process.SafeHandle, shellcodeReturnAddress); if ((NtStatus)shellcodeReturn != NtStatus.Success) { throw new RemoteFunctionCallException("Failed to call LdrLoadDll", (NtStatus)shellcodeReturn); } // Ensure the DLL is loaded before freeing any memory while (ProcessManager.Modules.TrueForAll(module => module.FilePath != DllPath)) { ProcessManager.Refresh(); } var dllPathAddress = ProcessManager.IsWow64 ? (IntPtr)MemoryManager.ReadVirtualMemory <UnicodeString32>(ProcessManager.Process.SafeHandle, dllPathUnicodeStringAddress).Buffer : (IntPtr)MemoryManager.ReadVirtualMemory <UnicodeString64>(ProcessManager.Process.SafeHandle, dllPathUnicodeStringAddress).Buffer; MemoryManager.FreeVirtualMemory(ProcessManager.Process.SafeHandle, dllPathAddress); MemoryManager.FreeVirtualMemory(ProcessManager.Process.SafeHandle, dllPathUnicodeStringAddress); MemoryManager.FreeVirtualMemory(ProcessManager.Process.SafeHandle, shellcodeReturnAddress); // Read the address of the DLL that was loaded in the remote process DllBaseAddress = MemoryManager.ReadVirtualMemory <IntPtr>(ProcessManager.Process.SafeHandle, moduleHandleAddress); MemoryManager.FreeVirtualMemory(ProcessManager.Process.SafeHandle, moduleHandleAddress); if (InjectionFlags.HasFlag(InjectionFlags.HideDllFromPeb)) { // Hide the DLL from the PEB of the remote process HideDllFromPeb(); } if (InjectionFlags.HasFlag(InjectionFlags.RandomiseDllHeaders)) { // Randomise the DLL headers RandomiseDllHeaders(DllBaseAddress); } }
private void CallFunctionInternal(FunctionCall functionCall) { // Write the shellcode used to perform the function call into the remote process var shellcode = Assembler.AssembleFunctionCall(functionCall); var shellcodeAddress = MemoryManager.AllocateVirtualMemory(Process.SafeHandle, IntPtr.Zero, shellcode.Length, MemoryProtectionType.ReadWrite); MemoryManager.WriteVirtualMemory(Process.SafeHandle, shellcodeAddress, shellcode); MemoryManager.ProtectVirtualMemory(Process.SafeHandle, shellcodeAddress, shellcode.Length, MemoryProtectionType.ExecuteRead); // Create a thread to execute the shellcode in the remote process var ntStatus = Ntdll.NtCreateThreadEx(out var threadHandle, Constants.ThreadAllAccess, IntPtr.Zero, Process.SafeHandle, Modules[0].BaseAddress, IntPtr.Zero, ThreadCreationFlags.CreateSuspended | ThreadCreationFlags.HideFromDebugger, 0, 0, 0, IntPtr.Zero); if (ntStatus != NtStatus.Success) { throw new PInvokeException("Failed to call NtCreateThreadEx", ntStatus); } if (IsWow64) { // Get the context of the thread var threadContext = new Context32 { ContextFlags = ContextFlags.Integer }; var threadContextBuffer = Marshal.AllocHGlobal(Marshal.SizeOf <Context32>()); Marshal.StructureToPtr(threadContext, threadContextBuffer, false); if (!Kernel32.Wow64GetThreadContext(threadHandle, threadContextBuffer)) { throw new PInvokeException("Failed to call Wow64GetThreadContext"); } threadContext = Marshal.PtrToStructure <Context32>(threadContextBuffer); // Change the spoofed start address to the address of the shellcode threadContext.Eax = (int)shellcodeAddress; Marshal.StructureToPtr(threadContext, threadContextBuffer, false); // Update the context of the thread if (!Kernel32.Wow64SetThreadContext(threadHandle, threadContextBuffer)) { throw new PInvokeException("Failed to call Wow64SetThreadContext"); } Marshal.FreeHGlobal(threadContextBuffer); } else { // Get the context of the thread var threadContext = new Context64 { ContextFlags = ContextFlags.Integer }; var threadContextBuffer = Marshal.AllocHGlobal(Marshal.SizeOf <Context64>()); Marshal.StructureToPtr(threadContext, threadContextBuffer, false); if (!Kernel32.GetThreadContext(threadHandle, threadContextBuffer)) { throw new PInvokeException("Failed to call GetThreadContext"); } threadContext = Marshal.PtrToStructure <Context64>(threadContextBuffer); // Change the spoofed start address to the address of the shellcode threadContext.Rcx = (long)shellcodeAddress; Marshal.StructureToPtr(threadContext, threadContextBuffer, false); // Update the context of the thread if (!Kernel32.SetThreadContext(threadHandle, threadContextBuffer)) { throw new PInvokeException("Failed to call SetThreadContext"); } Marshal.FreeHGlobal(threadContextBuffer); } Kernel32.ResumeThread(threadHandle); Kernel32.WaitForSingleObject(threadHandle, int.MaxValue); threadHandle.Dispose(); MemoryManager.FreeVirtualMemory(Process.SafeHandle, shellcodeAddress); }
/// <summary> /// Allocates a region of virtual memory in the remote process /// </summary> public IntPtr AllocateVirtualMemory(IntPtr baseAddress, int allocationSize, MemoryProtection protectionType = MemoryProtection.ExecuteReadWrite) { return(_memoryManager.AllocateVirtualMemory(baseAddress, allocationSize, protectionType)); }