一个程序的执行流程只是简单的演示下,如何实现一个HOOK在Net里面实现挂钩和在其他语言实现虽然在本质上是相同的,但细节上却是有点不同的
NET 采用的是事件驱动(消息机制的封装版),所有要实现一个消息的拦截,你必须实现
一个事件,而该事件的作用就是接受和处理
=======================================
1。开始我们定义一个基础类,实现一些基本的方法和变量
namespace Mr.Krcl.BaseHookLibrary
{
/*
hook library
by Mr.krcl 283018011
2010-5-12 BMD
: 这里给出的只是一个NET HOOK 模型 并未完全实现功能*/
// =================================================================
// 事件参数类
public class HookEventArgs: EventArgs
{
//根据需要你可以添加变量或函数实现功能的扩展
}
// ==================================================================
// 挂钩的消息类型,具体查阅MSDN
public enum HookType : int
{
WH_JOURNALRECORD = 0,
WH_JOURNALPLAYBACK = 1,
WH_KEYBOARD = 2,
WH_GETMESSAGE = 3,
WH_CALLWNDPROC = 4,
WH_CBT = 5,
WH_SYSMSGFILTER = 6,
WH_MOUSE = 7,
WH_HARDWARE = 8,
WH_DEBUG = 9,
WH_SHELL = 10,
WH_FOREGROUNDIDLE = 11,
WH_CALLWNDPROCRET = 12,
WH_KEYBOARD_LL = 13,
WH_MOUSE_LL = 14
}
// ====================================================================
// 导出API : 最烦人的工作了,不像C/C++其他语言直接调用头文件就OK
[DllImport("user32.dll")]
protected static extern IntPtr SetWindowsHookEx(HookType code,
HookProc func,
IntPtr hInstance,
int threadID)
[DllImport("user32.dll")]
protected static extern int UnhookWindowsHookEx(IntPtr hhook)
[DllImport("user32.dll")]
protected static extern int CallNextHookEx(IntPtr hhook,
int code, IntPtr wParam, IntPtr lParam)
// ====================================================================
// HOOK基类
public abstract class BaseHookLib:IDisposable{
// 事件委托 + 回调函数委托
public delegate CallBackHookProc(int nCode , IntPtr wparam ,IntPtr lparam)
public delegate HookEventHandler(object sender , HookEventArgs e)
public event HookEventHandler InvokeHook
// 构造函数
public BaseHookLib(HookType hType)
{
_hookType = hType
}
public BaseHookLib(HookType hType , CallBaseHookProc proc)
{
_hookType = hType
callBackFun = proc
}
// 内部变量
protected IntPtr _hhook = IntPtr.Zero
// 判断系统是否已经加载HOOK
protected bool _isHook = false
// 回调函数
protected CallBackHookProc callBackFun
// 挂钩消息的类型
protected HookType _hookType
public bool IsHook{
get {
return _isHook
}
}
// 引发时间
protected void OnHook(HookEventArgs e)
{
if(InvokeHook != null) InvokeHook(this , e)
}
// 钩子回调函数
protected int CallBackFunction(int nCode ,IntPtr wParam , IntPtr lparam)
{
if( nCode <0) return CallNextHookEx(_hhook , nCode , wParam ,lparam)
// 事件参数类实例化
HookEventArgs e = new HookEventArgs(....)
OnHook(e)
// ...............
// 这里可以做你想做的,作为基类我们总是直接返回
// ................
return CallNextHookEx(_hhook,nCode ,wParam ,lparam)
}
// 安装钩子
protected void InstallHook()
{
_hhook = SetWindowsHookEx(_hookType ,callbackFun ,
Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),,
0/*(int) AppDomain.GetCurrentThreadId()*/)
_hook = true
}
// 卸载钩子
protected void UnInstallHook()
{
UnhookWindowsHookEx(_hhook)
_hhook = IntPtr.Zero
_hook = false
}
// =============================================================================
//
// 继承IDisposable接口的目的在于实现Dispose方法 ,该接口继承可在派生类中实现继承
//
// =============================================================================
}现在我们需要做的就是关键步骤的了实现一个鼠标的HOOK类,该类从BaseHookLib中派生
namespace Mr.Krcl.BaseHookLibrary
{
// 鼠标时间参数类
public class MouseHookEventArgs{
/*
这里你可以通过添加任何可用的成员变量或方法来实现该类的扩展
当然你也可以同对MouseEventArgs类的继承来扩展,例如:
public class MouseHookEventArgs : MouseEventArgs{
...
}
*/
}
// =================================================================================
// 定义鼠标时间委托
// 委托的形式是可变的,这里我们遵循原始的鼠标委托写法
// public delegate void MouseEventHandler(object sender ,MouseEventArgs e)
public delegate void MouseHookEventHandler(object sender,MouseHookEventArgs e)
// =================================================================================
// 主打类 MouseHookLib
// 因为我们要继承BaseHookLib所有我们这里就不需要在进程IDISxxx接口了
public class MouseHookLib
{
// 构造函数
// HOOK鼠标消息的类型由基类负责传递,利用C#构造函数层分布特点
public MouseHookLib():base(HookType.WH_MOUSE_LL){
callBackFun = new CallBackHookProc(MouseHookCallBackFunction)
}
public MouseHookLib():base(HookType.WH_MOUSE_LL,new CallBackHookProc(MouseHookCallBackFunction){
}
// 析构函数
// 作用通过调用重载的Dispose函数卸载钩钩
~MouseHookLib(){
Dispose(false)
}
// 实现Dispose方法
// 如果你在基类已经实现了改方法那么,这里你需要采用重载方式实现,或者直接基类该方法
// 这里假设积累没有实现该方法
protected void Dispose( bool disposing )
{
if ( IsInstalled )
Uninstall() if ( disposing )
GC.SuppressFinalize( this )
}
public void Dispose()
{
Dispose( true )
}
/* 积累实现该方法后本类的重载实现
public override void Dispose( bool disposing )
{
if ( IsInstalled )
Uninstall() if ( disposing )
GC.SuppressFinalize( this )
}
*/
// 事件
// 定义了时间和事件的触发方法
// 单独的定义事件是毫无意义的
// 这里我们以定义两个事件MouseDown ,MouseMove为例,具体根据自己的需要,方法是相同
public event MouseHookEventHander MouseMove
public void OnMouseMove(MouseHookEventArgs e)
{
if(MouseMove != null){
MouseMove(this , e)
}
}
public event MouseHookEventHander MouseDown
public void OnMouseMove(MouseHookEventArgs e)
{
if(MouseDown != null){
MouseDown(this , e)
}
}
// 鼠标钩子回调函数
public IntPtr MouseHookCallBackFunction(int nCode , IntPtr wParam , IntPtr lparam)
{
if( nCode <0 ) return CallNextHookEx(_hhook , nCode ,wParam ,lParam)
MouseHookEventArgs e = new MouseHookEventArgs(.....)
/*
这里可以根据你自己的需要对拦截的消息进行过滤或者获取你自己需要的信息
例如:
if ( code == Win32.HC_ACTION ){
switch ( wParam.ToInt32() )
{
case Win32.WM_MOUSEMOVE:
OnMouseMove( e )
break
case Win32.WM_LBUTTONDOWN:
case Win32.WM_RBUTTONDOWN:
case Win32.WM_MBUTTONDOWN:
case Win32.WM_XBUTTONDOWN:
OnMouseDown( e )
break
}
}
这里只是一个模型 ,具体需要具体实现,关键就是根据lparam和wparam参数来实现事件的激活
从而调用事件,对目标消息进行拦截
*/
return CallNextHookEx(_hhook , nCode ,wParam ,lParam)
}
}
}
全局键盘钩子是需要放到dll中去实现的我估计你还不会写什么是dll
但有好消息告诉你
日志钩子可以做到在一个程序中实现全局键盘捕获:
VC代码:
#include<windows.h>
HHOOK LogHook=NULL
LRESULT CALLBACK LogProc(int code,WPARAM wParam,LPARAM lParam)
{
EVENTMSG *pEventMsg=(EVENTMSG*)lParam
if(code==HC_ACTION)
{
switch(pEventMsg->message)
{
case (WM_KEYDOWN):
BYTE bKeyState[256]
unsigned short uAscii[4]
UINT uScanCode
int iRet
GetKeyboardState(bKeyState)
bKeyState[VK_SHIFT]=GetKeyState(VK_SHIFT)
uScanCode=(pEventMsg->paramH>>16)
iRet=ToAscii(pEventMsg->paramL,uScanCode,bKeyState,uAscii,0)
switch(iRet)
{
case 0:
break
case 1:
if((char)uAscii[0]=='t' || (char)uAscii[0]=='T')//t键按下
{
MessageBox(NULL,"按下了T","按键提示",MB_OK)
/**************自己实现播放音乐的功能*****************/
}
else if((char)uAscii[0]=='y' || (char)uAscii[0]=='Y')//Y键按下
{
MessageBox(NULL,"按下了Y","按键提示",MB_OK)
/***************自己在这里实现停止播放音乐的功能****************/
}
break
default:
break
}
default:
break
}
}
return CallNextHookEx(LogHook,code,wParam,lParam)
}
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
{
LogHook=SetWindowsHookEx(WH_JOURNALRECORD,LogProc,hInstance,NULL)
while(1)Sleep(100)
return 0
}
日志钩子工作不稳定的。
你曾为公司不让用QQ MSN等聊天工具而烦恼吗?看了下面的小程序你就会打消这种看法了当初公司做校园一卡通的项目时 里面的机房客户端需要用到系统的低级键盘钩子WH_KEYBOARD_LL 这也是我第一次接触到Windows中的Hook 因为WH_KEYBOARD_LL和其他钩子不一样 在Delphi的Windows帮助以及windows pas文件中都没有定义 但microsoft的msdn中确有WH_KEYBOARD_LL的介绍 所以一路解决后就对Windows的系统钩子产生了兴趣 之后相继做过鼠标钩子WH_MOUSE 低级鼠标钩子WH_MOUSE_LL以及消息钩子WH_GETMESSAGE的小例子 都很有意思
这次我用到的是另外一个系统钩子 WH_CBT
看了delphi中的帮助 发现CBTProc中有很多功能
HCBT_ACTIVATEHCBT_CREATEWNDHCBT_DESTROYWNDHCBT_MINMAXHCBT_MOVESIZEHCBT_SETFOCUSHCBT_SYSMAND
(具体就不介绍了 看看帮助里写的很清楚)
随后便开始试验起来 最终完成了这个小程序 下面我简单介绍一下
运行程序后自动隐藏 当你提取QQ或者MSN的消息时会惊奇的发现聊天窗口的那个讨厌的 与XX聊天 的标题没有了 而标题换成了 我的文档 这时如果你再将此聊天窗口的图标换成文档样式的图标 那么谁还能看出那就是你的聊天窗口呢?(更换图标的方法也很多 可以用程序 也可以用软件直接修改QQ的资源文件 这部分我没有做 这里只是提供大家一个思路 有兴趣的朋友可以自己尝试一下 呵呵)
下面将代码帖出
library HookPrj
uses SysUtils Classes QQTitleHook in QQTitleHook pas
exportsEnableWheelHook DisableWheelHook
begin QQChat:= end unit QQTitleHook
interface
uses Windows Messages SysUtils Dialogs CommCtrl StrUtils
var QQChat: HHOOK //聊天窗口的句柄 hwQQChat: HWnd //聊天窗口的标题 tlQQChat: string //窗口类名 clsName: string buf: array [ ] of char
const//QQ聊天窗口的类名csQQ = #
function TitleHookProc(Code: IntegerwParam: WPARAMlParam: LPARAM): LRESULTstdcall function EnumWindowsTitleFunc(Handle: THandlelParam: LPARAM): boolean stdcall function EnableWheelHook : Booleanstdcallexport function DisableWheelHook: Booleanstdcallexport
implementation//钩子的处理函数 function TitleHookProc(Code: IntegerwParam: WPARAMlParam: LPARAM): LRESULTstdcall beginResult:= if Code<thenbegin Result:= CallNextHookEx(QQChat Code wParam lParam) Exitendelse if Code = HCBT_ACTIVATE then begin//获取激活窗口的句柄 以及窗口类名 然后判断此窗口类名是否为# hwQQChat:= HWND(wParam)GetClassName(hwQQChat buf )clsName:= string(buf)if clsName = csQQ thenbegin //如果窗口类名是# 则遍枚举所有窗口 并将窗口句柄传入//【这里仅仅做演示用 因为Windows中很多窗口的类名均为# 所以这样判断效率会很低】//【有兴趣的朋友可以根据QQ聊天窗口的特性来增加判断条件 从而提高效率 】 EnumWindows(@EnumWindowsTitleFunc hwQQChat)end endend
function EnumWindowsTitleFunc(Handle: THandlelParam: LPARAM): boolean stdcall beginif (Handle = lParam) and boolean(GetWindowText(Handle buf )) thenbegin //根据窗口句柄获得窗口标题 tlQQChat:= string(buf) //然后判断标题中是否包含 与 聊天 等相关字符 如果包括则此窗口为QQ聊天窗口 if ((pos( 与 tlQQChat)>) and (pos( 聊天中 tlQQChat)>)) then begin//确定为聊天窗口后遍修改窗口标题 tlQQChat := AnsiReplaceStr(tlQQChat 与 我的文档 )tlQQChat := AnsiReplaceStr(tlQQChat 聊天中 )SetWindowText(Handle pchar(tlQQChat)) end //【同上 这个地方大家可以自由控制 不仅仅局限在QQ MSN等聊天窗口 】 //【且想要将标题改成什么也可以自由控制 如果能根据修改后的窗口图标来确定标题】 //【比如通过修改将窗口图标替换成Delphi的图标 然后标题修改为Delphi 谁还能看出破绽呢?哈哈】 if ((pos( 群 - tlQQChat)>) or (pos( 高级群 - tlQQChat)>)) then begintlQQChat := AnsiReplaceStr(tlQQChat 群 - 我的文档 )tlQQChat := AnsiReplaceStr(tlQQChat 高级 )SetWindowText(Handle pchar(tlQQChat)) end //MSN if pos( 对话 tlQQChat)>then begintlQQChat := AnsiReplaceStr(tlQQChat 对话 我的文档 )SetWindowText(Handle pchar(tlQQChat)) endendResult :=True end
//启动钩子 function EnableWheelHook: Booleanstdcallexport beginif QQChat= thenbegin QQChat := SetWindowsHookEx(WH_CBT @TitleHookProc Hinstance ) Result := Trueendelse Result := Falseend
//卸载钩子function DisableWheelHook: Booleanstdcallexportbegin if QQChat<>then beginUnHookWindowsHookEx(QQChat)QQChat := Result := True end elseResult := False end
end
调用的应用程序就很简单了 调用EnableWheelHook后隐藏就可以了 退出时DisableWheelHook就OK啦
lishixinzhi/Article/program/Delphi/201311/24742
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)