CreateRemoteThread函数
创建在另一个进程的虚拟地址空间中运行的线程。
使用CreateRemoteThreadEx函数创建在另一个进程的虚拟地址空间中运行的线程,并可选择指定扩展属性。
语法
HANDLE CreateRemoteThread(HANDLE hProcess,LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId
);
参数
- hProcess
要创建线程的进程的句柄。句柄必须具有PROCESS_CREATE_THREAD,PROCESS_QUERY_INFORMATION,PROCESS_VM_OPERATION,PROCESS_VM_WRITE和PROCESS_VM_READ访问权限,并且在某些平台上没有这些权限时可能会失败。有关更多信息,请参阅 进程安全性和访问权限。
- lpThreadAttributes
指向SECURITY_ATTRIBUTES结构的指针,该 结构指定新线程的安全描述符,并确定子进程是否可以继承返回的句柄。如果lpThreadAttributes为NULL,则线程获取默认安全描述符,并且不能继承句柄。线程的默认安全描述符中的访问控制列表(ACL)来自创建者的主令牌。
Windows XP: 线程的默认安全描述符中的ACL来自创建者的主要或模拟令牌。Windows XP SP2和Windows Server 2003更改了此行为。
- dwStackSize
堆栈的初始大小,以字节为单位。系统将此值四舍五入到最近的页面。如果此参数为0(零),则新线程将使用可执行文件的默认大小。有关更多信息,请参阅 线程堆栈大小。
- lpStartAddress
指向由线程执行的LPTHREAD_START_ROUTINE类型的应用程序定义函数的指针,表示远程进程中线程的起始地址。该功能必须存在于远程进程中。有关更多信息,请参阅 ThreadProc。
- lpParameter
指向要传递给线程函数的变量的指针。
- dwCreationFlags
控制线程创建的标志。
值 | 含义 |
---|---|
0 | 该线程在创建后立即运行。 |
CREATE_SUSPENDED 0x00000004 | 线程是在挂起状态下创建的,并且在调用ResumeThread函数之前不会运行 。 |
STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000 | 所述dwStackSize参数指定堆栈的初始保留大小。如果未指定此标志,则dwStackSize指定提交大小。 |
- lpThreadId
指向接收线程标识符的变量的指针。
如果此参数为NULL,则不返回线程标识符。
返回值
如果函数成功,则返回值是新线程的句柄。
如果函数失败,则返回值为NULL。要获取扩展错误信息,请调用 GetLastError。
请注意,即使lpStartAddress指向数据,代码或无法访问, CreateRemoteThread也可能成功。如果线程运行时起始地址无效,则发生异常,并且线程终止。由于无效的起始地址导致的线程终止被视为线程进程的错误退出。此行为类似于CreateProcess的异步特性, 即使创建进程无效或缺少动态链接库(DLL),也会创建该进程。
备注
该远程线程函数会导致一个新的执行线程指定进程的地址空间开始。该线程可以访问进程打开的所有对象。
终端服务按设计隔离每个终端会话。因此,如果目标进程与调用进程位于不同的会话中,则 CreateRemoteThread将失败。
创建新的线程句柄,可以完全访问新线程。如果未提供安全描述符,则句柄可用于需要线程对象句柄的任何函数中。当提供安全描述符时,在授予访问权限之前,对句柄的所有后续使用执行访问检查。如果访问检查拒绝访问,则请求进程无法使用句柄来获取对线程的访问权限。
如果线程是在可运行状态下创建的(即,如果未使用CREATE_SUSPENDED标志),则线程可以在CreateThread返回之前开始运行,特别是在调用者接收到创建的线程的句柄和标识符之前。
创建的线程的线程优先级为THREAD_PRIORITY_NORMAL。使用 GetThreadPriority和 SetThreadPriority函数来获取和设置线程的优先级值。
当线程终止时,线程对象获得信号状态,该状态满足等待对象的线程。
线程对象保留在系统中,直到线程终止并且通过调用CloseHandle关闭它的所有 句柄。
ExitProcess, ExitThread, CreateThread, CreateRemoteThread的功能,以及正在启动一个过程(作为结果 的CreateProcess呼叫)的过程中彼此之间串行化。这些事件中只有一个一次发生在地址空间中。这意味着以下限制:
- 在进程启动和DLL初始化例程期间,可以创建新线程,但是在为进程执行DLL初始化之前它们不会开始执行。
- 进程中只有一个线程可以一次处于DLL初始化或分离例程中。
- 所有线程完成DLL初始化或分离例程后,ExitProcess返回。
此函数的一个常见用途是将线程注入正在调试的进程中以发出中断。但是,建议不要使用此方法,因为额外的线程会使调试应用程序的人感到困惑,并且使用此技术会产生一些副作用:
- 它将单线程应用程序转换为多线程应用程序。
- 它改变了进程的时序和内存布局。
- 它导致调用进程中每个DLL的入口点。
此函数的另一个常见用途是将一个线程注入进程以查询堆或其他进程信息。这可能会导致前一段中提到的相同副作用。此外,如果线程尝试获取另一个线程正在使用的锁的所有权,则应用程序可能会死锁。