dll远程注入
注入步骤:
远程注入是在远程进程中创建远程线程,并调用loadlibrary加载dll。
1、openProcess 打开远程进程
2、VirtualAllocEx 分配远程进程的地址空间中的内存
3、WriteProcessMemory 将dll路径名拷贝到第二步的内存中
4、GetProcAddress 获取LoadLibraryA/LoadLibraryW函数的实地址(kernel32.dll中)
5、CreateRemoteThread 创建远程线程,调用LoadLibrary传递第二部的内存地址
至此,被注入的dll的DllMain函数收到DLL_PROCESS_ATTACH通知。执行完DllMain函数时,远程线程从LoadLibrary返回到BaseThreadStart函数,然后BaseThreadStart调用ExitThread,使远程线程终止运行。
接下来是清理步骤:
6、VirtualFreeEx释放第二步申请的内存
7、GetProcAddress获取FreeLibrary函数的实地址
8、使用CreateRemoteThread创建远程线程,调用FreeLibrary,传递远程DLL的HINSTANCE
防注入:
当外部函数通过CreateRemoteThread创建远程线程,调用远程dll 的DllMain函数之前,会向该进程加载的本地dll发送DLL_THREAD_ATTACH 通知。
因此可以同在本地dll中判断,远程线程写入请求信息的函数是否是LoadLibrary。 线程+LoadLibrary可以判断该dll是远程注入。
BOOL VerifyDLLThread() {
NTQUERYINFORMATIONTHREAD NtQueryInformationThread =
(NTQUERYINFORMATIONTHREAD)GetProcAddress(GetModuleHandle(TEXT("ntdll")), "NtQueryInformationThread");
if (NtQueryInformationThread == NULL) {
return TRUE;
}
HANDLE hThread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, GetCurrentThreadId());
DWORD_PTR dwStaAddr = 0;
DWORD dwLength = 0;
MEMORY_BASIC_INFORMATION mbi = { 0 };
DWORD ret = NtQueryInformationThread(hThread, 9, &dwStaAddr, sizeof(dwStaAddr), &dwLength);
if (ret != 0) {
CloseHandle(hThread);
return TRUE;
}
if (s_loadlibrarya_addr == NULL) {
s_loadlibrarya_addr = (DWORD_PTR)GetProcAddress(LoadLibraryA("kernel32.dll"), "LoadLibraryA");
}
if (s_loadlibraryw_addr == NULL) {
s_loadlibraryw_addr = (DWORD_PTR)GetProcAddress(LoadLibraryA("kernel32.dll"), "LoadLibraryW");
}
if (s_loadlibraryexa_addr == NULL) {
s_loadlibraryexa_addr = (DWORD_PTR)GetProcAddress(LoadLibraryA("kernel32.dll"), "LoadLibraryExA");
}
if (s_loadlibraryexw_addr == NULL) {
s_loadlibraryexw_addr = (DWORD_PTR)GetProcAddress(LoadLibraryA("kernel32.dll"), "LoadLibraryExW");
}
if (dwStaAddr == s_loadlibrarya_addr ||
dwStaAddr == s_loadlibraryw_addr ||
dwStaAddr == s_loadlibraryexa_addr ||
dwStaAddr == s_loadlibraryexw_addr) {
CloseHandle(hThread);
return FALSE;
}
BOOL bVerifyResult = TRUE;
VirtualQueryEx(GetCurrentProcess(), (LPVOID)dwStaAddr, &mbi, sizeof(mbi));
if (mbi.State == MEM_COMMIT && mbi.Type != MEM_IMAGE) {
bVerifyResult = FALSE;
}
CloseHandle(hThread);
return bVerifyResult;
}
当然这样处理最多是提示,有远程注入。想要在这一步FreeLibrary是不行的。因为此时远程dll的DllMain函数还未执行,而TerminateThread也是失败。
最好的解决方案还是循环不断进行dll表的遍历检测,并且维护一个白名单,防止白名单以外的dll文件被加载。
参考:windows核心编程