常用的线程注入方法有:远程线程注入、普通消息钩子注入、全局消息钩子注入、APC 应用层异步注入、ZwCreateThreadEx 强力注入和纯汇编实现的线程注入等。
今天我们讲一下远程线程注入的这种方法,其原理是获取 LoadLibrary
系统函数的地址(我们知道系统函数的地址在每个进程中都是保持一致的,因此在我们自己进程中获取的系统函数地址同样适用于其他进程),通过调用 CreateRemoteThread
跨进程执行 LoadLibrary
将我们的 Dll 文件加载到目标地址空间内,实现注入。
step 1
首先我们需要打开目标进程,获取它的句柄:
HANDLE hProcess = NULL, hThread = NULL;
PSTR fileName = NULL;
FARPROC pfnThreadRtn = NULL;
// 打开注入进程,获取进程句柄
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid);
if (NULL == hProcess)
{
printf("打开进程失败\r\n");
return FALSE;
}
step 2
然后我们需要将 Dll 可执行文件的路径写入到目标地址空间内,否则在目标地址空间内调用 LoadLibrary
函数的时候找不到路径。
// 计算将注入 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;
}
step 3
将 Dll 路径写入到目标地址空间内后,我们需要获取 LoadLibrary
系统函数的地址:
// 在我们进程空间内获得 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 4
此时,我们就可以注入 Dll 了,通过执行 CreateRemoteThread
函数,跨进程调用目标函数中的 LoadLibrary
函数加载我们的 Dll 并等待加载成功:
// 使用 CreateRemoteThread 创建远程线程,注入 Dll
hThread = CreateRemoteThread(hProcess, NULL, 1024, (LPTHREAD_START_ROUTINE)pfnThreadRtn,
fileName, 0, NULL);
// 等待函数返回
WaitForSingleObject(hThread, INFINITE);
if (NULL != hThread)
{
CloseHandle(hThread);
CloseHandle(hProcess);
VirtualFreeEx(hProcess, fileName, 0, MEM_RELEASE);
return TRUE;
}
step 5
最后,在我们的主函数中调用即可:
int main()
{
// 尽量指定绝对路径(相对路径不知道为啥不行),且必须使用反斜杠
if (CreateRemoteThreadInjectDll(22212, "C:\\Users\\Administrator\\Desktop\\console_Dll.dll"))
{
printf("Dll 注入成功\r\n");
}
system("pause");
return 0;
}
注入结果如下: