常用的线程注入方法有:远程线程注入、全局消息钩子注入、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 _WIN64typedef 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);
#elsetypedef 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);
#endiftypedef_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;
}
效果如下: