前置回顾:线程基础
- 线程本质:依附于进程的代码执行流,进程至少有 1 个主线程 (main),可通过CreateThread新建子线程并发运行
- 线程函数标准格式
c
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
//线程执行代码
return 0;
}
- CreateThread 关键点
● 参数:安全属性、栈大小 (0 = 默认)、线程函数地址、线程参数、创建标志、TID 输出
● 线程句柄 CloseHandle不会杀死线程,只是释放句柄引用;线程生命周期由线程函数是否执行完毕决定
● 所有代码必须在线程内部才会被 CPU 调度执行,函数不会自动运行
CreateRemoteThread(远程线程 API)
- 定义
在另一个进程的虚拟地址空间创建并运行线程,也就是跨进程创建线程。
与CreateThread参数几乎完全一致,多了第一个参数 hProcess(目标进程句柄)
c
HANDLE CreateRemoteThread(
HANDLE hProcess, //【新增】目标进程句柄
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress, //线程函数地址:必须属于目标进程地址空间!
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);
- 使用完整步骤
- OpenProcess():打开目标进程,获取进程句柄,必须带上 PROCESS_CREATE_THREAD 权限
- CreateRemoteThread():在目标进程内创建远程线程
- 等待 / 观察线程执行(可选WaitForSingleObject等待线程结束)
- CloseHandle()关闭进程句柄、远程线程句柄
- 核心限制
lpStartAddress 线程函数地址必须是目标进程虚拟地址空间内的有效地址
不能直接传本进程函数地址!本进程的函数地址,在别的进程里面是无效的
经典用法:注入 DLL 时传入LoadLibraryA地址(LoadLibrary 在系统 dll,所有进程地址一致) - 安全特性
被叫做注入 "万恶之源"API,DLL 注入最经典 API
● 原理:在目标进程开远程线程,远程线程调用LoadLibrary加载我们的 dll,实现代码注入
● 风险:恶意程序大量用这个 API 做进程注入、木马
注意:高版本 Windows 有部分防护,现代对抗会规避 - CreateThread VS CreateRemoteThread
| 函数 | 运行位置 | 关键参数 |
|---|---|---|
| CreateThread | 当前本进程 | 不需要进程句柄,函数地址为本进程内地址 |
| CreateRemoteThread | 别的目标进程 | hProcess 目标进程句柄;线程函数地址属于目标进程 |
总结
- OpenProcess 打开目标进程,权限不够会直接创建远程线程失败
- 远程线程函数地址不能使用本地进程函数地址,地址空间隔离
- CloseHandle (hRemoteThread) 只是释放句柄,不会终止远程线程,线程继续跑完
- 远程线程执行在目标进程内,使用目标进程的栈、虚拟内存
c
//1.打开目标进程
HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION,
FALSE, dwPID); //dwPID是目标进程ID
//2.创建远程线程
HANDLE hRemoteThread = CreateRemoteThread(
hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)0x401090, //目标进程内函数地址
NULL,
0,
NULL);
//3.资源释放
CloseHandle(hRemoteThread);
CloseHandle(hProcess);
- CreateRemoteThread:跨进程创建线程,第一个参数是目标进程句柄 hProcess
- 线程入口地址必须属于目标进程地址空间,不能直接传本进程函数
- 经典用途:DLL 注入,也是恶意注入常用 API
- CloseHandle 只释放句柄,不终止正在运行的远程线程