看流星社区

 找回密码
 注册账号
查看: 2710|回复: 0

使用Detours对LoadLibraryExW进行HOOK屏蔽全局钩子

[复制链接]

该用户从未签到

发表于 2015-4-22 09:42:40 | 显示全部楼层 |阅读模式
全局钩子都是做为DLL挂接注入进程,假如应用程序A.exe安装了WH_GETMESSAGE的全局钩子,钩子函数在B.dll中,那么当其它程序在调用GetMessage函数从自己的消息队列中取消息的时候,系统发现程序A安装了WH_GETMESSAGE的全局钩子,就会检查调用GetMessage的进程是否加载了B.dll,如果没有,就调用LoadLibrary进行加载,然后调用B.dll中的钩子过程。这样,钩子dll就会在所有调用GetMessage的进程中加载。
如果程序本身能够对LoadLibrary进行处理,就能够防范其他DLL模块的注入。这里未经任何判断直接返回NULL,有点武断,会影响系统效率。
PS:上面这句话说了等于白说,现在谁还用这种方式啊,都是自己解析加载,要不就走LDR那套,这些都是老的不能再老的东西了,不过这里作为基础学习,还是粘下代码作为备忘了。
#include <Windows.h>  
#include <stdio.h>  
#include "detours.h"  
  
#pragma comment(lib, "detours.lib")  
#pragma warning(disable : 4098)  
  
static HMODULE (WINAPI* _LoadLibraryExW)(LPCTSTR lpFileName,HANDLE hFile,DWORD dwFlags) = LoadLibraryExW;  
  
VOID OutputDebugStringExW(const wchar_t* szFormat, ...)  
{  
    WCHAR Buffer[2048] = {0};  
  
    va_list argList;  
    va_start(argList, szFormat);  
    vswprintf(Buffer, sizeof(Buffer), szFormat, argList);  
    va_end(argList);  
  
    OutputDebugStringW(Buffer);  
}  
  
HMODULE WINAPI NEW_LoadLibraryExW(LPCTSTR lpFileName,HANDLE hFile,DWORD dwFlags)  
{  
    OutputDebugStringExW(L"%s", lpFileName);  
    return NULL;  
    //return _LoadLibraryExW(lpFileName, hFile, dwFlags);  
}  
  
VOID Hook()  
{  
    DetourRestoreAfterWith();  
    DetourTransactionBegin();  
    DetourUpdateThread(GetCurrentThread());  
  
    DetourAttach(&(PVOID&)_LoadLibraryExW, NEW_LoadLibraryExW ) ;  
  
    DetourTransactionCommit();  
}  
  
VOID UnHook()  
{  
    DetourTransactionBegin();  
    DetourUpdateThread(GetCurrentThread());  
  
    DetourDetach(&(PVOID&)_LoadLibraryExW, NEW_LoadLibraryExW );  
  
    DetourTransactionCommit();  
}  
  
BOOL APIENTRY DllMain(HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)  
{  
    if (ul_reason_for_call == DLL_PROCESS_ATTACH)  
    {   
        Hook();   
    }   
    else if (ul_reason_for_call == DLL_PROCESS_DETACH)   
    {   
        UnHook();  
    }   
    return TRUE;  
}  

以上是自己的DLL,如果需要对某个进程进行保护,只需要插入相关进程就好。当然相关进程如果不想麻烦,可以直接把HOOK过程写入程序代码。


经过调试发现,正常的加载dll函数调用都是从kernel32.dll中来的,而只有加载钩子过程是在user32.dll中进行的。可以对上面的函数进行修改,判断LoadLibrary函数的返回地址,如果是在user32.dll的地址空间,就认为是钩子dll的加载,直接返回NULL就可以了。
首先获取user32.dll的基地址
static DWORD m_dwUser32Low;    //user32.dll 的加载基址  
static DWORD m_dwUser32Hi;     //user32.dll 的加载基址+ImageSize  
  
MODULEINFO user32ModInfo = {0};  
  
//获取user32.dll的加载基址和映象大小   
GetModuleInformation(GetCurrentProcess(), GetModuleHandle("user32.dll"),   
                     &user32ModInfo, sizeof(user32ModInfo));  
m_dwUser32Low = (DWORD)user32ModInfo.lpBaseOfDll;  
m_dwUser32Hi = (DWORD)user32ModInfo.lpBaseOfDll+user32ModInfo.SizeOfImage;  

下面进行判断,如果来自user32.dll的调用直接进行返回。
HMODULE WINAPI NEW_LoadLibraryExW(LPCTSTR lpFileName,HANDLE hFile,DWORD dwFlags)  
{  
    //获取函数的返回地址  
    DWORD dwCaller;  
    __asm push dword ptr [ebp+4]  
    __asm pop  dword ptr [dwCaller]   
  
    //判断是否是从User32.dll调用的  
    if(dwCaller > m_dwUser32Low && dwCaller < m_dwUser32Hi)  
    {  
        OutputDebugStringExW(L"%s", lpFileName);  
        return NULL;  
    }  
      
    return _LoadLibraryExW(lpFileName, hFile, dwFlags);  
}  

PS:函数在调用的时候,先要把参数入栈,然后把返回地址入栈,esp指向的应该就是函数的返回地址了。但是为了返回函数时恢复原来的栈和在函数中方便引用传递的参数,编译器一般都会产生两条指令。
push ebp  
mov ebp,esp  
先把ebp入栈,把原来的esp保存在ebp寄存器中,这样,我们的返回地址就是[ebp+4],第一个参数是[ebp+8],第二个是[ebp+0xC]。
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-3-28 23:59

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

快速回复 返回顶部 返回列表