钩子及其应用(五)

本文给出了消息Spy的DLL源代码,包含公共数据结构单元和消息Spy的DLL代码。介绍了钩子过程、消息发送、共享内存创建等内容,还提及解决了进程间数据共享和通信问题,最后推荐了相关学习书籍。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下面就是DLL的源代码了:

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

unit wdSpyCommon;

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

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

* autor: linzhenqun

* date: <chsdate w:st="on" isrocdate="False" islunardate="False" day="25" month="9" year="2005">2005-9-25</chsdate>

* email: linzhengqun@163.com

* blog: http://blog.youkuaiyun.com/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: <chsdate w:st="on" isrocdate="False" islunardate="False" day="24" month="9" year="2005">2005-9-24</chsdate>

* email: linzhengqun@163.com

* blog: http://blog.youkuaiyun.com/linzhengqun

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

interface

uses

Messages, Windows, Classes, SysUtils, wdSpyCommon;

const

MapingFile_Name = 'MsgSpy_FC<chmetcnv w:st="on" tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="819" unitname="a">819A</chmetcnv>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、付费专栏及课程。

余额充值