下面就是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.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.
接着是消息Spy的DLL中的源代码:
unit wdMsgSpy;
{*******************************************
* brief: 消息Spy的SDK
* 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.csdn.net/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!
分享到:
相关推荐
以下是对钩子机制及其应用的详细解释: 一、钩子的基本概念: 钩子是Windows操作系统提供的一种机制,允许开发者注册函数来接收并处理特定的消息或事件。当特定的事件发生时,如键盘输入、窗口消息、系统事件等,...
本地钩子仅在安装它的进程上下文中运行,只能捕获该进程及其子进程中的键盘事件。而全局钩子则更为强大,可以在整个系统范围内工作,监听所有进程中发生的键盘事件。 实现键盘钩子通常涉及以下步骤: 1. 定义钩子...
下面将详细介绍几种常用的钩子类型及其应用场景: ##### 1. 键盘钩子与低级键盘钩子 **键盘钩子**(Keyboard Hook)用于监控所有键盘消息,包括按键按下与释放等事件。通过这种钩子,开发者可以实现对用户键盘输入...
在IT领域,尤其是在Windows应用程序开发中,"键盘钩子"和"鼠标钩子"是用于监控和处理系统级输入事件的重要技术。这些技术通常涉及到低级别编程,特别是使用C#语言时,EventHook库提供了方便的接口来实现这一功能。本...
总结起来,"hook_钩子程序-delphi"的主题涵盖了一个广泛的Delphi编程领域,涉及到Windows系统中的Hook技术及其在Delphi中的实现,这对于任何希望增强其应用程序功能或进行系统监控的开发者来说都是极其宝贵的资源。...
### 钩子函数在VC++中的应用 #### 一、引言 在软件开发过程中,特别是对于Windows应用程序而言,钩子(Hook)技术是一种非常有用的工具,...希望本文能够帮助初学者更好地理解和掌握钩子函数的基本原理及其应用场景。
在这个“完整版键盘钩子.rar”压缩包中,我们将会深入探讨键盘钩子的核心原理、实现方式及其在实际应用中的具体运用。 键盘钩子,简单来说,是一种操作系统级别的机制,允许程序拦截并处理键盘输入事件。这一技术...
这种实践可以帮助理解钩子的工作原理及其在实际项目中的应用。 在文件"钩子函数"中,可能包含了创建和使用钩子函数的代码示例。通过阅读和分析这些代码,你可以更深入地了解如何在实际编程中设置和管理钩子,以及...
本文重点介绍用户空间钩子的技术细节及其应用场景。 #### 三、用户空间钩子(User Space Hook) 用户空间钩子是在用户态下实现的一种Hook技术,主要用于拦截和修改应用程序的行为。这种技术通常不涉及对操作系统核心...
2. **应用程序级钩子**:局部钩子,只对创建它的进程及其子进程有效。 3. **线程级钩子**:针对特定线程的钩子,只会在指定线程中被调用。 二、钩子工作原理 当一个事件发生时,如键盘输入、鼠标点击,Windows会...
【标题】:深入理解钩子程序DLL及其在控制台中的应用 在Windows操作系统中,钩子(Hook)是一种系统机制,允许程序员监控特定事件的发生,例如键盘输入、鼠标操作等。钩子程序通常是一个动态链接库(DLL),它包含...
#### 一、全局钩子的概念及其重要性 在Windows操作系统中,全局钩子是一种强大的工具,它允许开发者在系统范围内捕获和处理各种消息。这对于创建诸如自动演示程序、程序日志、辅助调试工具等特殊功能极为有用。此外...
本篇文章将深入探讨消息钩子的实现及其在拦截`WM_COMMAND`消息中的应用。 首先,我们需要理解什么是`WM_COMMAND`消息。`WM_COMMAND`是Windows消息的一种,它在用户与菜单、快捷键、控件交互时产生,传递控制ID和...
全局键盘钩子是Windows操作系统提供的一种机制,允许应用程序在系统层面捕获键盘事件,即使焦点不在该应用程序上。这种技术通常用于实现系统级...通过分析和学习这段代码,可以加深对全局键盘钩子及其实现细节的理解。
全局钩子在所有当前运行于同一台计算机上的线程间共享,而本地钩子只对创建它的进程及其子进程有效。此外,还有WH_JOURNALPLAYBACK、WH_JOURNALRECORD、WH_KEYBOARD_LL、WH_MOUSE_LL等不同类型的钩子,它们分别针对...
本文将详细探讨MFC中的进程钩子及其使用方法。 首先,让我们理解什么是进程钩子。进程钩子是安装在特定进程中的,当该进程中发生特定事件时,钩子函数会被调用。这使得开发者可以在事件发生时进行干预,实现自定义...
### 鼠标键盘钩子技术详解及其应用 #### 一、钩子技术概述 钩子(Hook)技术是Windows操作系统提供的一种高级编程接口,它允许开发者捕获、拦截或修改系统中的各种消息和事件。通过钩子技术,开发者可以实现一些...
内容概要:本文介绍了 Vue3 的生命周期各个阶段以及各周期钩子的功能与调用时机,并详细讲解了这些生命周期的变化情况及与Vue2的区别,特别是对新增Composition API形式的生命周期做了细致解析和示例代码说明。...
钩子函数在Windows编程中是一种强大的机制,它允许开发者插入自定义代码到系统或应用程序的特定事件处理流程中,以实现对特定事件的监控或控制。在中文环境中,理解钩子函数的概念和使用方法对于Windows应用程序开发...
以下是几种常见的钩子类型及其作用: 1. **WH_CALLWNDPROC** 和 **WH_CALLWNDPROCRET Hooks**:这两个钩子允许你监控发送到窗口过程的消息。WH_CALLWNDPROC在消息被发送到接收窗口之前调用,WH_CALLWNDPROCRET则在...