钩子及其应用(五)

下面就是DLL的源代码了:

首先是声明一些共公的数据结构的单元,这个单元在DLL中用,也在程序中用的:

unit wdSpyCommon;

 

{*******************************************

 * brief: 消息Spy用到的数据结构等的声明文件

 * autor: linzhenqun

 * date: 2005-9-25

 * email: linzhengqun@163.com

 * blog: http://blog.csdn.net/linzhengqun

********************************************}

 

interface

uses

  Windows, Messages;

 

resourcestring

  err_ProcInvalid = 'the Message spy procedure are invalid.';

  err_ShareMem = 'could not create share memory.';

 

const

  Msg_Null_Value = 0;

  Msg_Type_Sent = 1;

  Msg_Type_Post = 2;

  Msg_Type_Return = 3;

 

type

  { 受监察的消息结构 }

  PMsgInfo = ^TMsgInfo;

  TMsgInfo = packed record

    hwnd: HWND;

    message: UINT;

    wParam: WPARAM;

    lParam: LPARAM;

    time: DWORD;

    pt: TPoint;

    lResult: LRESULT;

    MsgType: UINT;

  end;

 

implementation

 

end.

 

接着是消息SpyDLL中的源代码:

unit wdMsgSpy;

 

{*******************************************

 * brief: 消息SpySDK

 * autor: linzhenqun

 * date: 2005-9-24

 * email: linzhengqun@163.com

 * blog: http://blog.csdn.net/linzhengqun

********************************************}

 

interface

uses

  Messages, Windows, Classes, SysUtils, wdSpyCommon;

 

const

  MapingFile_Name = 'MsgSpy_FC 819A 73-2718-47E2-BF78-6810562CDA65';

 

type

  //共享内存

  PShareMem = ^TShareMem;

  TShareMem = record

    HRevWnd: THandle; //存放接收消息的窗口句柄

    HWndSpy: THandle; //被监察的窗口句柄

  end;

 

{ 开始监察消息,AHSpyWnd为受监察的窗口,AHRevWnd为接收监察到的消息的窗口 }

function StartSpyMessage(AHSpyWnd, AHRevWnd: THandle): Boolean; stdcall;

 

{ 停止监察消息 }

procedure StopSpyMessage; stdcall;

 

var

  HMsgProc, HWndProc, HWndRetProc: THandle; //相应钩子的句柄

  PSMem: PShareMem; //共享内存块

  hMapFile: THandle; //内存映射文件的句柄。

 

implementation

 

//将截获的消息结构发送到目标窗口

procedure SendData(AMsgInfo: PMsgInfo); stdcall;

var

  pcds: PCopyDataStruct;

begin

  New(pcds);

  pcds^.cbData := SizeOf(TMsgInfo);

  pcds^.lpData := AMsgInfo;

  SendMessage(PSMem^.HRevWnd, WM_COPYDATA, 0, LongInt(pcds));

  Dispose(pcds);

end;

 

{ WH_GETMESSAGE的钩子过程 }

function GetMsgProc(code: Integer; wP: WPARAM; lP: LPARAM): LRESULT; stdcall;

var

  LMsgInfo: PMsgInfo;

begin

{只有截获的消息的窗口句柄等于被监察的窗口句柄,才进行下一步,

接着,当被监察的窗口不是接收消息的窗口时执行下一步操作;或者当被监察窗口

就是接收消息的窗口时,截获的消息不是WM_CopyData,执行下一步。

这么做是为了避免进入发送消息与截获消息的死循环}

  if code = HC_ACTION then

    if (PMsg(lp)^.hwnd = PSMem^.HWndSpy) then

      if ((PSMem^.HWndSpy = PSMem^.HRevWnd) and (PMsg(lp)^.message <> WM_COPYDATA))

        or (PSMem^.HWndSpy <> PSMem^.HRevWnd) then

      begin

        New(LMsgInfo);

        LMsgInfo.hwnd := PMsg(lp)^.hwnd;

        LMsgInfo.message := PMsg(lp)^.message;

        LMsgInfo.wParam := PMsg(lp)^.wParam;

        LMsgInfo.lParam := PMsg(lp)^.lParam;

        LMsgInfo.pt := PMsg(lp)^.pt;

        LMsgInfo.time := PMsg(lp)^.time;

        LMsgInfo.lResult := Msg_Null_Value;

        LMsgInfo.MsgType := Msg_Type_Post;

        SendData(LMsgInfo);

        Dispose(LMsgInfo);

      end;

  Result := CallNextHookEx(HMsgProc, code, wP, lP);

end;

 

{ WH_CALLWNDPROC的钩子过程 }

function CallWndProc(code: Integer; wP: WPARAM; lP: LPARAM): LRESULT; stdcall;

var

  LMsgInfo: PMsgInfo;

begin

  if code = HC_ACTION then

    if (PCWPStruct(lp)^.hwnd = PSMem^.HWndSpy) then

      if ((PSMem^.HWndSpy = PSMem^.HRevWnd) and (PCWPStruct(lp)^.message <> WM_COPYDATA))

        or (PSMem^.HWndSpy <> PSMem^.HRevWnd) then

      begin

        New(LMsgInfo);

        LMsgInfo^.hwnd := PCWPStruct(lp)^.hwnd;

        LMsgInfo^.message := PCWPStruct(lp)^.message;

        LMsgInfo^.wParam := PCWPStruct(lp)^.wParam;

        LMsgInfo^.lParam := PCWPStruct(lp)^.lParam;

        LMsgInfo^.pt := Point(0, 0);

        LMsgInfo^.time := Msg_Null_Value;

        LMsgInfo^.lResult := Msg_Null_Value;

        LMsgInfo^.MsgType := Msg_Type_Sent;

        SendData(LMsgInfo);

        Dispose(LMsgInfo);

      end;

  Result := CallNextHookEx(HWndProc, code, wP, lP);

end;

 

{ WH_CALLWNDPROCRET的钩子过程 }

function CallWndRetProc(code: Integer; wP: WPARAM; lP: LPARAM): LRESULT; stdcall;

var

  LMsgInfo: PMsgInfo;

begin

  if code = HC_ACTION then

      if (PCWPRetStruct(lp)^.hwnd = PSMem^.HWndSpy) then

        if ((PSMem^.HWndSpy = PSMem^.HRevWnd) and (PCWPRetStruct(lp)^.message <> WM_COPYDATA))

          or (PSMem^.HWndSpy <> PSMem^.HRevWnd) then

        begin

          New(LMsgInfo);

          LMsgInfo^.hwnd := PCWPRetStruct(lp)^.hwnd;

          LMsgInfo^.message := PCWPRetStruct(lp)^.message;

          LMsgInfo^.wParam := PCWPRetStruct(lp)^.wParam;

          LMsgInfo^.lParam := PCWPRetStruct(lp)^.lParam;

          LMsgInfo^.pt := Point(0, 0);

          LMsgInfo^.time := Msg_Null_Value;

          LMsgInfo^.lResult := PCWPRetStruct(lp)^.lResult;

          LMsgInfo^.MsgType := Msg_Type_Return;

          SendData(LMsgInfo);

          Dispose(LMsgInfo);

      end;

  Result := CallNextHookEx(HWndRetProc, code, wP, lP);

end;

 

 

function StartSpyMessage(AHSpyWnd, AHRevWnd: THandle): Boolean;

begin

  Result := False;

  try

    if (HMsgProc <> 0) or (HWndProc <> 0) or (HWndRetProc <> 0) then

      Exit;

    PSMem^.HWndSpy := AHSpyWnd;

    PSMem^.HRevWnd := AHRevWnd;

    HMsgProc := SetWindowsHookEx(WH_GETMESSAGE, @GetMsgProc, HInstance, 0);

    HWndProc := SetWindowsHookEx(WH_CALLWNDPROC, @CallWndProc, HInstance, 0);

    HWndRetProc := SetWindowsHookEx(WH_CALLWNDPROCRET, @CallWndRetProc, HInstance, 0);

    if (HMsgProc = 0) or (HWndProc = 0) or (HWndRetProc = 0) then

    begin

      StopSpyMessage;

      Exit;

    end;

  except

    Exception.Create(err_ProcInvalid);

  end;

  Result := True;

end;

 

procedure StopSpyMessage;

begin

  UnhookWindowsHookEx(HMsgProc);

  UnhookWindowsHookEx(HWndProc);

  UnhookWindowsHookEx(HWndRetProc);

  HMsgProc := 0;

  HWndProc := 0;

  HWndRetProc := 0;

end;

 

initialization

 //创建共享内存块

  hMapFile := OpenFileMapping(FILE_MAP_ALL_ACCESS, False, MapingFile_Name);

  if hMapFile = 0 then

    hMapFile := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0,

      SizeOf(TShareMem), MapingFile_Name);

  PSMem :=  MapViewOfFile(hMapFile, FILE_MAP_WRITE or FILE_MAP_READ, 0, 0, 0);

  if PSMem = nil then

  begin

    CloseHandle(hMapFile);

    Exception.Create(err_ShareMem);

  end;

 

finalization

 //释放共享内存块

  UnMapViewOfFile(PSMem);

  CloseHandle(hMapFile);

 

end.

 

解决了上面的技术问题,再来看源代码是很容易理解的,就钩子的安装和解除本身很简单,难的是进程间的数据共享和通信问题。但这些现在已经不是问题了,不是吗。

 

DLL的导出函数当然就是:

exports

  StartSpyMessage,

  StopSpyMessage;

然后在显示消息的窗口截获WM_COPYDATA,处理显示的问题就行了。不过WM_COPYDATA其他窗口也可以发送的,所以处理WM_COPYDATA的过程一定要作一下异常处理才行。

 

好了,要完整的程序代码,请发邮件给我吧:linzhengqun@163.com

 

后记

这真是一篇很长的文章,写这篇文章的过程也是自我提高的过程,学到非常多的东西。在这里推荐几本书,能够更系统的学到这些知识:

首先当然是《Windows高级编程第四版》,没有另一本书能够讲得比这本更精彩深入了。研究底层的读者必读之书。

其次是《Delphi5开发人员指南》,其中有关于日志钩子的应用以及内存映射文件的用法,可以一看。

还有一些网上的文章,也值得借鉴,但我总觉得讲不到重点去,比如全局钩子,希望这一篇能够让读者更好的运用全局钩子。

 

我在努力,我在进步,希望你们也是。Happy programme

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值