使用英语阅读

通过


CreateRemoteThreadEx 函数 (processthreadsapi.h)

创建在另一个进程的虚拟地址空间中运行的线程,并选择性地指定扩展属性,例如处理器组相关性。

语法

HANDLE CreateRemoteThreadEx(
  [in]            HANDLE                       hProcess,
  [in, optional]  LPSECURITY_ATTRIBUTES        lpThreadAttributes,
  [in]            SIZE_T                       dwStackSize,
  [in]            LPTHREAD_START_ROUTINE       lpStartAddress,
  [in, optional]  LPVOID                       lpParameter,
  [in]            DWORD                        dwCreationFlags,
  [in, optional]  LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,
  [out, optional] LPDWORD                      lpThreadId
);

参数

[in] hProcess

要在其中创建线程的进程句柄。 句柄必须具有PROCESS_CREATE_THREAD、PROCESS_QUERY_INFORMATION、PROCESS_VM_OPERATION、PROCESS_VM_WRITE和PROCESS_VM_READ访问权限。 在 Windows 10 版本 1607 中,代码必须获取新句柄的这些访问权限。 但是,从 Windows 10 版本 1703 开始,如果新句柄有权访问这些访问权限,系统将为你获取它们。 有关详细信息,请参阅 进程安全性和访问权限

[in, optional] lpThreadAttributes

指向 SECURITY_ATTRIBUTES 结构的指针,该结构指定新线程的安全描述符,并确定子进程是否可以继承返回的句柄。 如果 lpThreadAttributes 为 NULL,则线程将获取默认的安全描述符,并且无法继承句柄。 线程的默认安全描述符中的访问控制列表(ACL)来自创建者的主要令牌。

[in] dwStackSize

堆栈的初始大小(以字节为单位)。 系统将此值舍入到最近的页面。 如果此参数为 0(零),则新线程使用可执行文件的默认大小。 有关详细信息,请参阅 线程堆栈大小

[in] lpStartAddress

指向由线程执行的 LPTHREAD_START_ROUTINE 类型的应用程序定义的函数的指针,表示远程进程中线程的起始地址。 函数必须存在于远程进程中。 有关详细信息,请参阅 ThreadProc

[in, optional] lpParameter

指向要传递给 lpStartAddress所指向的线程函数的变量的指针。 此参数可以为 NULL。

[in] dwCreationFlags

控制线程创建的标志。

价值 意义
0
创建后,线程会立即运行。
CREATE_SUSPENDED
0x00000004
线程以挂起状态创建,在调用 ResumeThread 函数之前不会运行。
STACK_SIZE_PARAM_IS_A_RESERVATION
0x00010000
dwStackSize 参数 指定堆栈的初始保留大小。 如果未指定此标志,dwStackSize 指定提交大小。

[in, optional] lpAttributeList

一个属性列表,其中包含新线程的其他参数。 此列表由 InitializeProcThreadAttributeList 函数创建。

[out, optional] lpThreadId

指向接收线程标识符的变量的指针。

如果此参数为 NULL,则不返回线程标识符。

返回值

如果函数成功,则返回值是新线程的句柄。

如果函数失败,则返回值为 NULL。 若要获取扩展的错误信息,请调用 GetLastError

言论

CreateRemoteThreadEx 函数会导致在指定进程的地址空间中开始执行的新线程。 线程有权访问进程打开的所有对象。 lpAttribute 参数可用于指定扩展属性,例如新线程的处理器组相关性。 如果 lpAttribute 为 NULL,则该函数的行为与 createRemoteThread相同。

在 Windows 8 之前,终端服务按设计隔离每个终端会话。 因此,如果目标进程与调用进程位于不同的会话中,CreateRemoteThread 失败。

新线程句柄是使用对新线程的完全访问权限创建的。 如果未提供安全描述符,则句柄可用于任何需要线程对象句柄的函数。 提供安全描述符后,在授予访问权限之前,对句柄的所有后续使用执行访问检查。 如果访问检查拒绝访问,则请求进程无法使用句柄获取对线程的访问权限。

如果线程处于可运行状态(即未使用CREATE_SUSPENDED标志),则线程可以在 CreateThread 返回之前开始运行,尤其是在调用方收到创建的线程的句柄和标识符之前。

该线程是使用线程优先级THREAD_PRIORITY_NORMAL创建的。 若要获取和设置线程的优先级值,请使用 GetThreadPrioritySetThreadPriority 函数。

当线程终止时,线程对象将达到信号状态,该状态满足等待对象的线程。

线程对象一直保留在系统中,直到线程终止并且所有句柄通过调用关闭 CloseHandle

ExitProcessExitThreadCreateThreadCreateRemoteThread 函数以及启动进程(CreateProcess 调用的结果)在进程中相互序列化。 一次地址空间中只发生其中一个事件。 这意味着以下限制保留:

  • 在进程启动和 DLL 初始化例程期间,可以创建新线程,但在为进程完成 DLL 初始化之前,它们不会开始执行。
  • 一个进程中只有一个线程可以同时在 DLL 初始化或分离例程中。
  • ExitProcess 在所有线程完成 DLL 初始化或分离例程后返回。
此函数的常见用途是将线程注入正在调试以发出中断的进程。 但是,不建议使用此用法,因为额外的线程对调试应用程序的用户感到困惑,并且使用此技术会产生几个副作用:
  • 它将单线程应用程序转换为多线程应用程序。
  • 它会更改进程的计时和内存布局。
  • 这会导致调用进程中每个 DLL 的入口点。
此函数的另一个常见用途是将线程注入进程以查询堆或其他进程信息。 这可能会导致上一段提到的相同副作用。 此外,如果线程尝试获取另一个线程正在使用的锁的所有权,应用程序可能会死锁。

要求

要求 价值
最低支持的客户端 Windows 7 [仅限桌面应用]
支持的最低服务器 Windows Server 2008 R2 [仅限桌面应用]
目标平台 窗户
标头 processthreadsapi.h (包括 Windows Server 2008 Windows Server 2008 R2 上的 Windows.h)
Kernel32.lib
DLL Kernel32.dll

另请参阅

CreateRemoteThread