首页  编辑  

系统挂钩捕捉键盘操作

Tags: /超级猛料/Hook.钩子/   Date Created:
在许多系统中,出于安全或其它原因,常常要求随时对键盘进行监控,一个专 业的监控程序必须具备两点,一是实时;二是作为指示图标运行。实际应用中把利 用Hook(即钩子)技术编写的应用程序添加到Windows的任务栏的指示区中就能够 很好的达到这个目的。我在参考了API帮助文档基础上,根据在Delphi开发环境中 的具体实现分别对这两部分进行详细论述。
一、Hook(钩子)的实现:
---- Hook是应用程序在Microsoft Windows 消息处理过程中设置的用来监控消息流并且处理系统中尚未到达目的窗口的某一类型消息过程的机制。如果Hook过程在应用程序中实现,若应用程序不是当前窗口时,该Hook就不起作用;如果Hook在DLL中实现,程序在运行中动态调用它,它能实时对系统进行监控。根据需要,我们采用的是在DLL中实现Hook的方式。
---- 1.新建一个导出两个函数的DLL文件,在hookproc.pas中定义了钩子具体实现过 程。代码如下:
 library keyspy;

uses
  windows, messages, hookproc in 'hookproc.pas';

exports setkeyhook, endkeyhook;

begin
  nexthookproc := 0;
  procsaveexit := exitproc;
  exitproc := @keyhookexit;
end.
2.在Hookproc.pas中实现了钩子具体过程:  
unit hookproc;

interface

uses
  Windows, Messages, SysUtils, Controls, StdCtrls;

var
  nexthookproc: hhook;
  procsaveexit: pointer;
function keyboardhook(icode: integer; wparam: wparam; lparam: lparam): lresult;
  stdcall; export;
function setkeyhook: bool; export; // 加载钩子
function endkeyhook: bool; export; // 卸载钩子
procedure keyhookexit; far;

const
  afilename = 'c:\debug.txt'; // 将键盘输入动作写入文件中

var
  debugfile: textfile;

implementation

function keyboardhookhandler(icode: integer; wparam: wparam; lparam: lparam)
  : lresult; stdcall; export;
begin
  if icode < 0 then
  begin
    result := callnexthookex(hnexthookproc, icode, wparam, lparam);
    exit;
  end;
  assignfile(debugfile, afilename);
  append(debugfile);
  if getkeystate(vk_return) < 0 then
  begin
    writeln(debugfile, '');
    write(debugfile, char(wparam));
  end
  else
    write(debugfile, char(wparam));
  closefile(debugfile);
  result := 0;
end;

function endkeyhook: bool; export;
begin
  if nexthookproc <> 0 then
  begin
    unhookwindowshookex(nexthookproc);
    nexthookproc := 0;
    messagebeep(0);
  end;
  result := hnexthookproc = 0;
end;

procedure keyhookexit; far;
begin
  if nexthookproc <> 0 then
    endkeyhook;
  exitproc := procsaveexit;
end;

end.
---- 二、Win95/98使用任务栏右方指示区来显示应用程序或工具图标对指示区图标的操作涉及了一个API函数Shell_NotifyIcon,它有两个参数,一个是指向TnotifyIconData结构的指针,另一个是要添加、删除、改动图标的标志。通过该函函数将应用程序的图标添加到指示区中,使其作为图标运行,增加专业特色。当程序起动后,用鼠标右键点击图标,则弹出一个菜单,可选择sethook或endhook。
unit kb;

interface

uses
  Windows, Messages, SysUtils, Classes,
  Graphics, Controls, Forms,
  Dialogs, StdCtrls, Menus, shellapi;

const
  icon_id = 1;
  MI_iconevent = wm_user + 1; // 定义一个用户消恿

type
  TForm1 = class(TForm)
    PopupMenu1: TPopupMenu;
    sethook1: TMenuItem;
    endhook1: TMenuItem;
    N1: TMenuItem;
    About1: TMenuItem;
    Close1: TMenuItem;
    Gettext1: TMenuItem;
    procedure FormCreate(Sender: TObject);
    procedure sethook1Click(Sender: TObject);
    procedure endhook1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Close1Click(Sender: TObject);
  private
    { Private declarations } nid: tnotifyicondata;
    normalicon: ticon;
  public
    { Public declarations }
    procedure icontray(var msg: tmessage); message MI_iconevent;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}
function setkeyhook: bool; external 'keyspy.dll';
function endkeyhook: bool; external 'keyspy.dll';

procedure TForm1.icontray(var msg: tmessage);
var
  pt: tpoint;
begin
  if msg.lparam = wm_lbuttondown then
    sethook1Click(self);
  if msg.lparam = wm_rbuttondown then
  begin
    getcursorpos(pt);
    setforegroundwindow(handle);
    PopupMenu1.popup(pt.x, pt.y);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  normalicon := ticon.create;
  application.title := caption;
  nid.cbsize := sizeof(nid);
  nid.wnd := handle;
  nid.uid := icon_id;
  nid.uflags := nif_icon or nif_message or nif_tip;
  nid.ucallbackmessage := MI_iconevent;
  nid.hIcon := normalicon.handle;
  strcopy(nid.sztip, pchar(caption));
  nid.uflags := nif_message or nif_icon or nif_tip;
  shell_notifyicon(nim_add, @nid);
  SetWindowLong(application.handle, GWL_EXSTYLE, WS_EX_TOOLWINDOW);
end;

procedure TForm1.sethook1Click(Sender: TObject);
begin
  setkeyhook;
end;

procedure TForm1.endhook1Click(Sender: TObject);
begin
  endkeyhook;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  nid.uflags := 0;
  shell_notifyicon(nim_delete, @nid);
end;

procedure TForm1.Close1Click(Sender: TObject);
begin
  application.terminate;
end;
---- 该程序虽然只用了几个shellai函数,但是它涉及到了在Delphi中对DLL的引 用、钩子实现、对指示区的操作、用户定义消息的处理、文件的读写等比较重要的 内容,我相信这篇文章能对许多Delphi的初学者有所帮助。
---- 该程序在Win98、Delphi4.0中正常运行。