Hook是Windows中提供的一种用以替换DOS下“中断”的系统机制,中文译为“挂钩”或“钩子”。在对特定的系统事罩皮世件进行hook后,一旦发生已hook事件,对该事件进行hook的程序就会受到系统的通知,这时程序就能在第一时间对该事件做出响应。
另一解释:
钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。
钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。
Hook原理
每一个Hook都有一个与之相关联的指针列表,称之为钩子链表,由系统来维护。这个列表的指针指向指定的,应用程序定义的,被Hook子程调用的回调函数,也就是该钩子的各个处理子程。当与指定的Hook类型关联的消息发生时,系统就把这个消息传递到Hook子程。一些Hook子程可以只监视消息,或者修改消息,或者停止消息的前进,避免这些消息传递到下一个Hook子程或者目的窗口。最近安装的钩子放在链的开始,而最早安装的钩子放在最后,也就是后加入的先获得控制权。
Windows 并不要求钩子子程的卸载顺序一定得和安装顺序相反。每当有一个钩子被卸载,Windows 便释放其占用的内存,并更新整个Hook链表。如果程序安装了钩子,但是在尚未卸载钩子之前就结束了,那么系统会自动为它做卸载钩子的 *** 作。
钩子子程是一握纯个应用程序定义的回调函数(CALLBACK Function),不能定义成某个类的成员函数,只能定义为普通的C函数。用以监视系统或某一特定类型的事件,这些事件可以是与某一特定线程关联的,也可以是系统中所有线程的事件。
系统钩子与线程钩子
SetWindowsHookEx()函数的最后一个参数决定了此钩子是系统钩子还是线程钩子。
线程勾子用于监视指定线程的事件消息。线程勾子一般在当前线程或者当前线程派生的线程内。
系统勾子监视系统中的所有线程的事件消息。因为系统勾子会影响系统中所有的应用程序,所以勾子函数必须放在独立的动态链接库(DLL) 中。系统自动将包含“钩子回调函数”的DLL映射到受钩子函数影响的所有进程的地址空间中,即将这个DLL注入了那些进程。
几点说明:
(1)如果对于同一事件(如鼠标消息物肢)既安装了线程勾子又安装了系统勾子,那么系统会自动先调用线程勾子,然后调用系统勾子。
(2)对同一事件消息可安装多个勾子处理过程,这些勾子处理过程形成了勾子链。当前勾子处理结束后应把勾子信息传递给下一个勾子函数。
(3)勾子特别是系统勾子会消耗消息处理时间,降低系统性能。只有在必要的时候才安装勾子,在使用完毕后要及时卸载。
Hook的应用模式
观察模式
最为常用,像Windows提供的SetWindowHook就是典型地为这类应用准备的。而且这也是最普遍的用法。
这个模式的特点是,在事情发生的时候,发出一个通知信息。观察者只可以查看过程中的信息,根据自己关心的内容处理自己的业务,但是不可以更改原来的流程。
如全局钩子中,经常使用的鼠标消息、键盘消息的监视等应用。金山词霸屏幕取词的功能是一个典型的应用(具体技术可以参考此类文章)。
注入模式
这个模式和观察模式最大的不一样的地方在于,注入的代码是为了扩展原始代码的功能业务。插件模式是此类模式的典型案例。
不管瘦核心的插件系统(如Eclipse)还是胖核心的插件系统(如Delphi、Visual Studio等IDE环境),其对外提供的插件接口都是为了扩展本身系统的功能的。
这种扩展的应用方式的典型特点,就是新的扩展代码和原来的代码会协调处理同类业务。
替换模式
如果针对应用目的不同,可以叫修复模式或破解模式。前者是为了修改系统中的BUG,后者是为了破解原有系统的限制。
很多黑客使用此种模式,将访问加密锁的DLL中的导出表,替换成自己的函数,这样跳过对软件的控制代码。这类应用的难点是,找出函数的参数。
这类模式的特点是,原有的代码会被新的代码所替换。
前面三个是基本模式,还有很多和实际应用相关的模式。
集权模式
此类模式的出现,大都是为了在全部系统中,统一处理某类事情。它的特点不在于注入的方式,而在于处理的模式。
这个模式,大都应用到某类服务上,比如键盘服务,鼠标服务,打印机服务等等特定服务上。通过统一接管此类服务的访问,限制或者协调对服务的访问。
比如键盘锁功能的实现,就是暂时关闭键盘的所有应用。
这类模式的特点主要会和特点服务有关联。
修复模式
替换模式的一种,这里强调的是其应用的目的是为了修复或扩展原有系统的功能。
破解模式
替换模式的一种,这里强调的是其应用的目的是为了跳过原有系统的一部分代码。如加密检测代码,网络检测代码等等。
插件模式
注入模式的一种,在系统的内部直接依靠HOOK机制进行扩展业务功能。
共享模式
这类应用中,经常是为了获取对方的数据。必然我希望获取对方系统中,所有字符串的值。可以通过替换对方的内存管理器,导出所有字符串。
这个应用比较特殊。不过其特点在于,目的是达到系统之间的数据共享。
其实现,可能是观察模式,也可能是替换模式。
VB中的Hook技术应用
一、Hook简介
Hook这个东西有时令人又爱又怕,Hook是用来拦截系统某些讯息之用,例如说,我们想
让系统不管在什么地方只要按个Ctl-B便执行NotePad,或许您会使用Form的KeyPreview
,设定为True,但在其他Process中按Ctl-B呢?那就没有用,这是就得设一个Keyboard
Hook来拦截所有Key in的键;再如:MouseMove的Event只在该Form或Control上有效,如果希望在Form的外面也能得知Mouse Move的讯息,那只好使用Mouse Hook来栏截Mouse
的讯息。再如:您想记录方才使用者的所有键盘动作或Mosue动作,以便录巨集,那就
使用JournalRecordHook,如果想停止所有Mosue键盘的动作,而放(执行)巨集,那就
使用JournalPlayBack Hook;Hook呢,可以是整个系统为范围(Remote Hook),即其他
Process的动作您也可以拦截,也可以是LocalHook,它的拦截范围只有Process本身。
Remote Hook的Hook Function要在.Dll之中,Local Hook则在.Bas中。
在VB如何设定Hook呢?使用SetWindowsHookEx()
Declare Function SetWindowsHookEx Lib 'user32' Alias 'SetWindowsHookExA' _
(ByVal idHook As Long, _
ByVal lpfn As Long, _
ByVal hmod As Long, _
ByVal dwThreadId As Long) As Long
idHook代表是何种Hook,有以下几种
Public Const WH_CALLWNDPROC = 4
Public Const WH_CALLWNDPROCRET = 12
Public Const WH_CBT = 5
Public Const WH_DEBUG = 9
Public Const WH_FOREGROUNDIDLE = 11
Public Const WH_GETMESSAGE = 3
Public Const WH_HARDWARE = 8
Public Const WH_JOURNALPLAYBACK = 1
Public Const WH_JOURNALRECORD = 0
Public Const WH_KEYBOARD = 2
Public Const WH_MOUSE = 7
Public Const WH_MSGFILTER = (-1)
Public Const WH_SHELL = 10
Public Const WH_SYSMSGFILTER = 6
lpfn代表Hook Function所在的Address,这是一个CallBack Fucnction,当挂上某个
Hook时,我们便得定义一个Function来当作某个讯息产生时,来处理它的Function
,这个Hook Function有一定的叁数格式
Private Function HookFunc(ByVal ncode As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
nCode 代表是什么请况之下所产生的Hook,随Hook的不同而有不同组的可能值
wParam lParam 传回值则随Hook的种类和nCode的值之不同而不同。
因这个叁数是一个 Function的Address所以我们固定将Hook Function放在.Bas中,
并以AddressOf HookFunc传入。至于Hook Function的名称我们可以任意给定,不一
定叫 HookFunc
hmod 代表.DLL的hInstance,如果是Local Hook,该值可以是Null(VB中可传0进去),
而如果是Remote Hook,则可以使用GetModuleHandle('.dll名称')来传入。
dwThreadId 代表执行这个Hook的ThreadId,如果不设定是那个Thread来做,则传0(所以
一般来说,Remote Hook传0进去),而VB的Local Hook一般可传App.ThreadId进去
值回值如果SetWindowsHookEx()成功,它会传回一个值,代表目前的Hook的Handle,
这个值要记录下来。
因为A程式可以有一个System Hook(Remote Hook),如KeyBoard Hook,而B程式也来设一
个Remote的KeyBoard Hook,那么到底KeyBoard的讯息谁所拦截?答案是,最后的那一个
所拦截,也就是说A先做keyboard Hook,而后B才做,那讯息被B拦截,那A呢?就看B的
Hook Function如何做。如果B想让A的Hook Function也得这个讯息,那B就得呼叫
CallNextHookEx()将这讯息Pass给A,于是产生Hook的一个连线。如果B中不想Pass这讯息
给A,那就不要呼叫CallNextHookEx()。
Declare Function CallNextHookEx Lib 'user32' _
(ByVal hHook As Long, _
ByVal ncode As Long, _
ByVal wParam As Long, _
lParam As Any) As Long
hHook值是SetWindowsHookEx()的传回值,nCode, wParam, lParam则是Hook Procedure
中的三个叁数。
最后是将这Hook去除掉,请呼叫UnHookWindowHookEx()
Declare Function UnhookWindowsHookEx Lib 'user32' (ByVal hHook As Long) As Long
hHook便是SetWindowsHookEx()的传回值。此时,以上例来说,B程式结束Hook,则换A可
以直接拦截讯息。
KeyBoard Hook的范例
Hook Function的三个叁数
nCode wParam lParam 传回值
HC_ACTION 表按键Virtual Key 与WM_KEYDOWN同 若讯息要被处理传0
或 反之传1
HC_NOREMOVE
Public hHook As Long
Public Sub UnHookKBD()
If hnexthookproc <> 0 Then
UnhookWindowsHookEx hHook
hHook = 0
End If
End Sub
Public Function EnableKBDHook()
If hHook <> 0 Then
Exit Function
End If
hHook = SetWindowsHookEx(WH_KEYBOARD, AddressOf MyKBHFunc, App.hInstance, App.ThreadID)
End Function
Public Function MyKBHFunc(ByVal iCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
MyKBHFunc = 0 '表示要处理这个讯息
If wParam = vbKeySnapshot Then '侦测 有没有按到PrintScreen键
MyKBHFunc = 1 '在这个Hook便吃掉这个讯息
End If
Call CallNextHookEx(hHook, iCode, wParam, lParam) '传给下一个Hook
End Function
只要将上面代码放在VB的模块中,用标准VB程序就可以了,当运行该程序后,就能拦截所有键盘 *** 作。
没有关系,初级的慎败物时枯缺候,就是这样。
先把别人的程序拿来,然后,自己把它分析明白。
一边宽液看书,一边上机练习。
一定要多多练习。
C#写HOOK还是延续WINDOWS HOOK的思路的,使用标准的API :SetWindowHookEx....思路很简单:写个类自己定义一个钩子事件然后再自己程序中调用,下面是我以前写的一个NET HOOK框架,网上相圆此掘关资源也是很多的======================================写多了其他语言实现的HOOK,突然很想写个不一样的,想来想去Net HOOK是最合适的了使用的方法还是传统的 Gui‘Thread Hook : SetWindowsHookEx/CallNextHookExHOOK -- 拦截,一种改变程序执行流程的技术手段,这里我不想过多的去谈如果去改变一个程序的执行流程只是简单的演示下,如何实现一个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)
}
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)