zoukankan      html  css  js  c++  java
  • 第21章:Windows消息钩取

    Windows向用户提供GUI,以事件驱动的方式工作.

    常规的Windows消息流:

    发生键盘输入事件时,WM_KeyDown消息被添加到OS消息队列.

    OS判断哪个应用程序发生了事件,然后从OS消息队列重取出消息,添加到应用程序的消息队列中.

    应用程序监视自身的消息队列,发现新添加的消息后,调用相应的事件处理程序处理.

    SetWindowsHookEx()可以实现消息钩取.

    第一个参数是钩子类型,例如可以为 WH_KeyBoard ,键盘钩子.

    第二个参数是钩子过程,是由操作系统调用的回调函数,说白了就是处理程序.

    第三个参数是钩子过程所属的DLL句柄,因为钩子过程需要存在于某个DLL内部.

    第四个参数代表想要影响的进程,若为0则影响所有进程.

    可执行程序加载并安装钩子 -> 其它进程发生硬盘输入事件 -> OS将Dll文件加载到相应得进程内存 -> 调用回调函数

    重点看一下HookMain.exe文件的源代码.

    #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)();   //声明一个返回值为NULL的函数指针
    
    void main()
    {
        HMODULE            hDll = NULL;
        PFN_HOOKSTART    HookStart = NULL;    //定义函数指针
        PFN_HOOKSTOP    HookStop = NULL;    //函数指针赋值为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();
    printf("press 'q' to quit! "); while( _getch() != 'q' ) ; // 终止钩取 HookStop(); // 卸载KeyHook.dll FreeLibrary(hDll); }
    #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)    //此处猜测是覆写了KeyBoardProc()函数
    {
        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, '\');     //返回字符串中从右侧搜索首次出现字符 \ 的地址。
    
               
                if( !_stricmp(p + 1, DEF_PROCESS_NAME) )    //字符串相等时,返回值为0
                    return 1;                               //程序为notepad.exe时,直接返回1即不将键盘按键数据传到应用程序
            }
        }
    
        // 若当前进程名称不是notepad.exe则调用 CallNextHookEx() 函数,将消息传递给应用程序或下一个钩子
        return CallNextHookEx(g_hHook, nCode, wParam, lParam);
    }
    
    #ifdef __cplusplus
    extern "C" {
    #endif
        __declspec(dllexport) void HookStart()             //declspec是针对编译器的关键字,指出相应函数为导出函数
        {
            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

    安装好键盘钩子之后,无论哪个进程发生键盘输入事件,OS会将KeyHook.dll注入到相应进程,而此进程发生键盘事件时也会首先调用执行 KeyHook.KeyboardProc()

    Printf()函数看着简单,其实挺复杂的.

  • 相关阅读:
    UnQLite简介
    .net中webconfig自定义配置
    webservice有关application/xop+xml的异常
    .NET4缓存过期策略摘录
    关于sea.js的笔记
    npm笔记和bower
    使用npm安装一些包失败了的看过来(npm国内镜像介绍)
    easyui的datagird动态设置当前页数
    Oracle中Merge into用法总结
    Oracle 12.1.0.2 对JSON的支持
  • 原文地址:https://www.cnblogs.com/Rev-omi/p/13361775.html
Copyright © 2011-2022 走看看