远程线程注入
远程线程注入是一种常见的注入手段,是一种跨进程创建线程的注入手法。
其实现思路是将待注入DLL的路径写入目标进程内存空间,并利用CreateRemoteThread和LoadLibrary函数使目标进程创建一个线程,将其入口地址设为LoadLibrary,进而加载待注入的DLL。
DLL_THREAD_ATTACH通知
通过查阅《Windows核心编程》和微软说明文档得知:
当进程创建一个线程的时候,系统会检查当前映射到该进程的地址空间中的所有DLL文件映像,并用DLL_THREAD_ATTACH来调用每个DLL的DllMain函数,调用是在新线程的上下文中进行的。新创建的线程负责执行所有DLL的DllMain函数中的代码,只有当所有DLL都完成了对该通知的处理之后,系统才会让新线程开始执行它的线程函数。
远程线程注入检测
我们可以利用DLL_THREAD_ATTACH通知这一机制来检测远程线程注入。方法如下:
创建一个DLL,在DllMain的DLL_THREAD_ATTACH这一switch分支下拦截每一个新创建的线程,获取其如入口地址,将入口地址与LoadLibrary函数地址作比较,若相同,则说明是远线程注入创建的线程。
DllMain代码如下:
DllMain
#include<Windows.h>
#include<TlHelp32.h>
typedef enum _THREADINFOCLASS {
ThreadQuerySetWin32StartAddress=9
}THREADINFOCLASS;
typedef LONG(WINAPI* LPFN_ZWQUERYINFORMATIONTHREAD)(
IN HANDLE ThreadHandle,
IN THREADINFOCLASS ThreadInformationClass,
OUT PVOID ThreadInformation,
IN ULONG ThreadInformationLength,
OUT PULONG ReturnLength OPTIONAL);
void Check_RemoteThreadInject(DWORD dwStartAddr)
{
DWORD dwAddr_LoadLibraryA = (DWORD)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "LoadLibraryA");
DWORD dwAddr_LoadLibraryW = (DWORD)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "LoadLibraryW");
DWORD dwAddr_LoadLibraryExA= (DWORD)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "LoadLibraryExA");
DWORD dwAddr_LoadLibraryExW = (DWORD)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "LoadLibraryExW");
if (dwStartAddr == dwAddr_LoadLibraryA || dwStartAddr == dwAddr_LoadLibraryW||
dwStartAddr == dwAddr_LoadLibraryExA || dwStartAddr== dwAddr_LoadLibraryExW)
{
if (MessageBoxA(0, "find remote thread inject\nkill or not?", "tips", MB_OKCANCEL) == IDOK)
{
ExitThread(0);
}
}
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_THREAD_ATTACH:
DWORD dwStartAddr, dwReturnLen;
HINSTANCE hNTDLL = GetModuleHandleA("ntdll.dll");
LPFN_ZWQUERYINFORMATIONTHREAD ZwQueryInformationThread = (LPFN_ZWQUERYINFORMATIONTHREAD)GetProcAddress(hNTDLL, "ZwQueryInformationThread");
ZwQueryInformationThread(GetCurrentThread(), //查询线程起始地址
ThreadQuerySetWin32StartAddress,
&dwStartAddr,
4,
&dwReturnLen);
Check_RemoteThreadInject(dwStartAddr); //判断是否是远程线程注入的线程
break;
}
return TRUE;
}
结果测试
在主进程中加载该DLL并用注入器向主进程注入DLL进行测试,测试结果如下: