常用的线程注入方法有:远程线程注入、全局消息钩子注入、APC 应用层异步注入 和 ZwCreateThreadEx 强力注入等。
今天我们讲一下ZwCreateThreadEx 强力注入的这种方法。之前的远程线程通过 CreateRemoteThread
函数来进行 Dll 注入,这种方式可以注入普通的进程,但是却无法注入到系统进程中,因为系统进程是处在 SESSION0 高权限级别的会话层。
由于 CreateRemoteThread
底层实际上会调用 ZwCreateThreadEx
这个未公开的内核函数,该内核函数在 ntdll.dll
中,所以我们必须通过 GetProcAddress
函数将其地址导出。
step 1
和远程线程注入的前面步骤类似,要想跨进程调用 LoadLibaray
函数,首先我们必须把需要加载的 Dll 路径写入到目标进程地址空间,然后获取 LoadLibrary
函数在目标进程空间的地址:
HANDLE hProcess = NULL;
PSTR fileName = NULL;
FARPROC pfnThreadRtn = NULL;
HANDLE hRemoteThread = NULL;
// 打开注入进程,获取进程句柄
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid);
if (NULL == hProcess)
{
printf("打开进程失败\r\n");
return FALSE;
}
// 计算将注入 Dll 文件的完整路径长度
SIZE_T fileNameLen = strlen(DllName) + 1;
// 在目标空间申请一块长度为 fileNameLen 大小的内存空间
fileName = (PSTR)VirtualAllocEx(hProcess, NULL, fileNameLen, MEM_COMMIT, PAGE_READWRITE);
if (NULL == fileName)
{
CloseHandle(hProcess);
printf("在目标空间申请内存空间失败\r\n");
return FALSE;
}
// 将 Dll 文件的完整路径写入目标进程申请的空间内
if (FALSE == WriteProcessMemory(hProcess, fileName, (PVOID)DllName, fileNameLen, NULL))
{
VirtualFreeEx(hProcess, fileName, 0, MEM_RELEASE);
CloseHandle(hProcess);
printf("将完整路径写入目标进程空间失败\r\n");
return FALSE;
}
// 在我们进程空间内获得 LoadLibrary 函数的地址
pfnThreadRtn = GetProcAddress(GetModuleHandle(L"Kernel32"), "LoadLibraryA");
if (NULL == pfnThreadRtn)
{
VirtualFreeEx(hProcess, fileName, 0, MEM_RELEASE);
CloseHandle(hProcess);
printf("获取 LoadLibrary 函数地址失败\r\n");
return FALSE;
}
step 2
然后,由于 ZwCreateThreadEx
函数在 ntdll.dll
中是未导出的,因此我们需要把该模块加载进去,然后再获取函数地址:
// 加载 ntdll.dll
HMODULE hNtModule = LoadLibraryA("ntdll.dll");
if (NULL == hNtModule)
{
VirtualFreeEx(hProcess, fileName, 0, MEM_RELEASE);
CloseHandle(hProcess);
printf("加载 hNtModule 模块失败\r\n");
return FALSE;
}
step 3
获取函数地址之前,我们需要定义一个函数指针用来接收函数地址。由于该函数在 32 位和 64 位系统下的定义是不一样的,所以我们定义函数指针也要对应才可以,然后通过 GetProcAddress
获取函数地址:
// 定义一个函数指针,并从 ntdll.dll 中获取 ZwCreateThread 函数地址
#ifdef _WIN64
typedef DWORD(WINAPI* typedef_ZwCreateThreadEx)(
PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
LPVOID ObjectAttributes,
HANDLE ProcessHandle,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
ULONG CreateThreadFlags,
SIZE_T ZeroBits,
SIZE_T StackSize,
SIZE_T MaximumStackSize,
LPVOID pUnkown);
#else
typedef DWORD(WINAPI* typedef_ZwCreateThreadEx)(
PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
LPVOID ObjectAttributes,
HANDLE ProcessHandle,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
BOOL CreateSuspended,
DWORD dwStackSize,
DWORD dw1,
DWORD dw2,
LPVOID pUnkown);
#endif
typedef_ZwCreateThreadEx ZwCreateThreadEx =
(typedef_ZwCreateThreadEx)GetProcAddress(hNtModule, "ZwCreateThreadEx");
step 4
准备工作完毕后,就可以进行注入了:
// 使用 ZwCreateThreadEx 创建远程线程,实现强力注入 Dll 文件
int status = ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess,
(LPTHREAD_START_ROUTINE)pfnThreadRtn, fileName, 0, 0, 0, 0, NULL);
if (NULL == hRemoteThread)
{
CloseHandle(hNtModule);
VirtualFreeEx(hProcess, fileName, 0, MEM_RELEASE);
CloseHandle(hProcess);
printf("使用 ZwCreateThreadEx 函数注入 Dll 失败\r\n");
return FALSE;
}
step 5
最后,我们来调用注入函数:
int main()
{
if (ZwCreateThreadInjectDll(1068,
"C:\\Users\\Administrator\\Desktop\\console_Dll.dll"))
{
printf("注入成功\r\n");
}
system("pause");
return 0;
}
效果如下: