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); }