2021-03-07

windows消息钩取

1.钩子与消息钩子
windows操作系统向用户提供GUI,它以事件驱动方式工作。在操作系统中借助键盘,鼠标,选择菜单,按钮以及移动鼠标,改变窗口大小与位置都是事件。发生事件时,OS会将事先定义好的消息发送给相应的应用程序。

常规Windows消息流:

1.发生键盘输入事件,WM_KEYDOWN消息被添加到OS消息队列;
2.OS判断哪个应用程序发生了事件,从OS消息队列中取出消息,添加到相应应用程序的app消息队列;
3.应用程序监视自身的消息队列,发现新添加的WM_KEYDOWN消息,调用相应的事件处理程序进行处理。

附带钩子的信息流:

1.发生键盘输入事件,WM_KEYDOWN消息被添加到OS消息队列;
2.OS判断哪个应用程序发生了事件,从OS消息队列中取出消息,发送给应用程序;
3.钩子程序截取信息,对消息采取一定的动作(因钩子目的而定);
4.如钩子程序不拦截消息,消息最终传输给应用程序,此时的消息可能经过了钩子程序的修改。

OS消息队列与应用程序消息队列之间存在一条钩链,设置好键盘消息钩子之后,处于钩链中的键盘消息钩子会比应用程序先看到相应的信息。在键盘消息钩子的内部,除了可以查看消息之外,还可以修改消息本身实施拦截,阻止信息传递

在这里插入图片描述
2.SetWindowsHookEx()
这是一个实现消息钩子的API,其定义如下:

HHOOK SetWindowsHookEx(
        int idHook,                                                // hook type
        HOOKpROC lpfn,                                // hook procedure
        HINSTANCE hMod,                                //hook procedure所属的DLL句柄
        DWORD dwThreadId                        //需要挂钩的线程ID,为0时表示为全局钩子(Global Hook)
);

hook proceduce是由操作系统调用的回调函数;安装消息钩子时,钩子过程需要存在于某个DLL内部,且该DLL的示例句柄即为hMod。

使用SetWindowsHookEx()设置好钩子后,在某个进程中生成指定消息时,OS就会将相关的DLL文件强制注入(injection)相应进程,然后调用注册的钩子程序。

三、键盘消息钩取
在这里插入图片描述
KeyHook.dll文件是一个含有钩子过程的dll文件。HookMain.exe是最先加载KeyHook.dll并安装键盘钩子的程序,HookMain.exe加载KeyHook.dll后使用SetWindowsHookEx()安装键盘钩子;若其他进程(如图中所示)发生键盘输入事件,OS就会强制将KeyHook.dll加载到像一个进程的内存,然后调用KeyboardProc()函数。

3.HookMain.cpp

#include "stdio.h"
#include "conio.h"
#include "windows.h"

#define        DEF_DLL_NAME                "KeyHook.dll"
#define        DEF_HOOKSTART                "HookStart"
#define        DEF_HOOKSTOP                "HookStop"

typedef void (*PFN_HOOKSTART)();
typedef void (*PFN_HOOKSTOP)();

void main()
{
        HMODULE        hDll = NULL;
        PFN_HOOKSTART        HookStart = NULL;
        PFN_HOOKSTOP        HookStop = NULL;
        char        ch = 0;

  // 加载KeyHook.dll
        hDll = LoadLibraryA(DEF_DLL_NAME);
    if( hDll == NULL )
    {
        printf("LoadLibrary(%s) failed!!! [%d]", DEF_DLL_NAME, GetLastError());
        return;
    }

  // 获取导出函数地址
        HookStart = (PFN_HOOKSTART)GetProcAddress(hDll, DEF_HOOKSTART);
        HookStop = (PFN_HOOKSTOP)GetProcAddress(hDll, DEF_HOOKSTOP);

  // 开始钩取
        HookStart();

  // 等待,直到用户输入“q”
        printf("press 'q' to quit!\n");
        while( _getch() != 'q' )        ;

  // 终止钩子
        HookStop();

  // 卸载KeyHook.dll
        FreeLibrary(hDll);
}
[/mw_shl_code]

### 2. KeyHook.dll

KeyHook.dll源代码:

[mw_shl_code=cpp,true]
#include "stdio.h"
#include "windows.h"

#define DEF_PROCESS_NAME                "notepad.exe"

HINSTANCE g_hInstance = NULL;
HHOOK g_hHook = NULL;
HWND g_hWnd = NULL;

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
{
        switch( dwReason )
        {
        case DLL_PROCESS_ATTACH:
                        g_hInstance = hinstDLL;
                        break;

        case DLL_PROCESS_DETACH:
                        break;        
        }

        return TRUE;
}

LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
        char szPath[MAX_PATH] = {0,};
        char *p = NULL;

        if( nCode >= 0 )
        {
                // bit 31 : 0 => press, 1 => release
                if( !(lParam & 0x80000000) )        //释放键盘按键时
                {
                        GetModuleFileNameA(NULL, szPath, MAX_PATH);
                        p = strrchr(szPath, '\\');

      //比较当前进程名称是否为notepad.exe,成立则消息不传递给应用程
                        if( !_stricmp(p + 1, DEF_PROCESS_NAME) )
                                return 1;
                }
        }

  //如果不是notepad.exe,则调用CallNextHookEx()函数,将消息传递给应用程序
        return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}

#ifdef __cplusplus
extern "C" {
#endif
        __declspec(dllexport) void HookStart()
        {
                g_hHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hInstance, 0);
        }

        __declspec(dllexport) void HookStop()
        {
                if( g_hHook )
                {
                        UnhookWindowsHookEx(g_hHook);
                        g_hHook = NULL;
                }
        }
#ifdef __cplusplus
}
#endif

用od打开exe文件
在这里插入图片描述
因为程序中有明显的字符串“press ‘q’ to quit!”,所以先检查程序导入的字符串(Search for -All referencen text strings)

在这里插入图片描述
在这里插入图片描述
在401000处下断,开始调试,401006地址处调用LoadLibraryA(Keyhook.dll),然后由40104b地址处的CALL EBX指令调用KeyHook.HookStart()函数。
在这里插入图片描述
图中代码是被加载到HookMain.exe进程中的KeyHook.dllHookStart()函数。在100010EF地址处可以看到CALL SetWindowsHookExW()指令,其上方100010E8与100010ED地址处的2条PUSH指令用于将SetWindowsHookExW()API的第一,二两个参数压入栈中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值