如何向ZwCreateThreadEx例程传递参数?含HANDLE与UNICODE_STRING示例
如何给ZwCreateThreadEx的线程函数传递HANDLE和UNICODE_STRING参数?
兄弟,我明白你现在的需求——之前的代码能创建无参数的隐藏线程,但现在要给线程函数传HANDLE和UNICODE_STRING类型的参数对吧?其实核心思路很简单:因为ZwCreateThreadEx的线程入口函数只接受一个LPVOID类型的参数,所以我们可以把多个需要传递的参数打包成一个自定义结构体,然后把这个结构体的指针作为参数传入,在线程函数内部再把指针转换回结构体类型,就能拿到我们需要的参数了。
下面是具体的实现步骤和完整代码示例:
1. 定义包含目标参数的结构体
首先我们要定义一个结构体,把需要传递的HANDLE和UNICODE_STRING都放进去:
// 自定义参数结构体,包含需要传递的两种类型参数 typedef struct _THREAD_PARAMS { HANDLE hTargetHandle; UNICODE_STRING usTargetString; } THREAD_PARAMS, *PTHREAD_PARAMS;
2. 修改线程函数以接收并解析参数
把原来的线程函数改成接收结构体指针的形式,然后从结构体里取出我们需要的参数:
void WINAPI ContinueExecution(LPVOID param) { // 将传入的LPVOID参数转换为我们的结构体指针 PTHREAD_PARAMS pParams = (PTHREAD_PARAMS)param; // 现在就可以使用结构体里的参数了 printf("线程已启动,传入的HANDLE值: 0x%p\n", pParams->hTargetHandle); // 打印UNICODE_STRING内容(注意要转换为多字节字符串方便输出) char szBuffer[256] = {0}; WideCharToMultiByte(CP_ACP, 0, pParams->usTargetString.Buffer, pParams->usTargetString.Length / sizeof(WCHAR), szBuffer, sizeof(szBuffer), NULL, NULL); printf("传入的字符串内容: %s\n", szBuffer); // 如果参数是堆分配的,记得在线程结束前释放(根据实际分配方式调整) HeapFree(GetProcessHeap(), 0, param); }
3. 准备参数并调用ZwCreateThreadEx
在主函数里,我们需要实例化这个结构体,填充参数,然后把结构体指针作为StartParameter传递给ZwCreateThreadEx:
#include "stdafx.h" #include <conio.h> #include <windows.h> #include <Winternl.h> #pragma comment(lib,"ntdll.lib") // 这里放上面定义的_THREAD_PARAMS结构体和ContinueExecution函数 int main() { // 1. 准备要传递的参数 THREAD_PARAMS* pThreadParams = (THREAD_PARAMS*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(THREAD_PARAMS)); if (!pThreadParams) { printf("分配参数内存失败!\n"); return -1; } // 填充HANDLE参数(这里用当前进程的句柄作为示例) pThreadParams->hTargetHandle = GetCurrentProcess(); // 填充UNICODE_STRING参数(这里初始化一个示例字符串) WCHAR szTestString[] = L"Hello from hidden thread!"; pThreadParams->usTargetString.Buffer = szTestString; pThreadParams->usTargetString.Length = wcslen(szTestString) * sizeof(WCHAR); pThreadParams->usTargetString.MaximumLength = (wcslen(szTestString) + 1) * sizeof(WCHAR); // 2. 调用ZwCreateThreadEx创建线程 HANDLE hHiddenThread = NULL; NTSTATUS status = ZwCreateThreadEx( &hHiddenThread, THREAD_ALL_ACCESS, NULL, GetCurrentProcess(), (PTHREAD_START_ROUTINE)ContinueExecution, pThreadParams, // 这里传递我们的结构体指针作为参数 FALSE, 0, 0, 0, NULL ); if (NT_SUCCESS(status)) { printf("隐藏线程创建成功!线程句柄: 0x%p\n", hHiddenThread); // 等待线程执行完成(可选,根据需求调整) WaitForSingleObject(hHiddenThread, INFINITE); CloseHandle(hHiddenThread); } else { printf("创建线程失败,NTSTATUS: 0x%X\n", status); HeapFree(GetProcessHeap(), 0, pThreadParams); } _getch(); return 0; }
关键注意事项
- 参数的生命周期:如果结构体是在栈上分配的(比如局部变量),要确保主线程不会在线程函数执行完之前退出或者销毁这个栈变量,否则线程函数会访问到无效内存。所以更安全的方式是用
HeapAlloc在堆上分配结构体,就像示例里那样,然后在线程函数结束前释放。 - UNICODE_STRING的缓冲区:如果
UNICODE_STRING的Buffer是动态分配的(比如用HeapAlloc分配的宽字符串),也要确保在线程函数里正确释放,避免内存泄漏。 - 类型转换:在线程函数里一定要把
LPVOID正确转换为我们的结构体指针,否则会出现类型错误或者内存访问异常。
内容的提问来源于stack exchange,提问作者user9672569
相关产品推荐
相关产品推荐

