`

.net 的hook 设计

    博客分类:
  • .net
阅读更多

今天,有个同事问我,怎样在C#中使用全局钩子?以前写的全局钩子都是用unmanaged C或C++写个DLL来实现,可大家都知道,C#是基于.Net Framework的,是managed,怎么实现全局钩子呢?于是开始到网上搜索,好不容易找到一篇,318804 - HOW TO: Set a Windows Hook in Visual C# .NET,里面详细的说明了如何使用鼠标钩子捕获鼠标的移动等,可是,它只能在Application里起作用,出了Application就没用了,就是说它还是没有实现全局钩子,而且文章结尾处说:“Global Hooks are not supported in the .NET Framework...”,这可怎么办呢?

  别担心,办法总是有的,经过一番摸索以后,发现WH_KEYBORAD_LL和WH_MOUSE_LL这两个low-level的hook可以被安装成全局的,这就好办了,我们不妨用这两个low-level的hook替换掉WH_KEYBORAD和WH_MOUSE,于是开始测试。结果成功了,在C#里实现了全局钩子。

  我们来看一下主要代码段。

  首先倒入所需要的windows函数,主要有三个,SetWindowsHookEX用来安装钩子,UnhookWindowsHookEX用来卸载钩子以及CallNextHookEX用来将hook信息传递到链表中下一个hook处理过程。

[DllImport("user32.dll", CharSet = CharSet.Auto,
           CallingConvention 
= CallingConvention.StdCall, SetLastError = true)]
        
private static extern int SetWindowsHookEx(
            
int idHook,
            HookProc lpfn,
            IntPtr hMod,
            
int dwThreadId);

[DllImport(
"user32.dll", CharSet = CharSet.Auto,
            CallingConvention 
= CallingConvention.StdCall, SetLastError = true)]
        
private static extern int UnhookWindowsHookEx(int idHook);

[DllImport(
"user32.dll", CharSet = CharSet.Auto,
             CallingConvention 
= CallingConvention.StdCall)]
        
private static extern int CallNextHookEx(
            
int idHook,
            
int nCode,
            
int wParam,
            IntPtr lParam);

  下面是有关这两个low-level hook在Winuser.h中的定义:

/// <summary>
        
/// Windows NT/2000/XP: Installs a hook procedure that monitors low-level mouse input events.
        
/// </summary>

        private const int WH_MOUSE_LL       = 14;
        
/// <summary>
        
/// Windows NT/2000/XP: Installs a hook procedure that monitors low-level keyboard  input events.
        
/// </summary>

        private const int WH_KEYBOARD_LL    = 13;

  在安装全局钩子的时候,我们就要做替换了,将WH_MOUSE和WH_KEYBORAD分别换成WH_MOUSE_LL和WH_KEYBORAD_LL:

//install hook
                hMouseHook = SetWindowsHookEx(
                    WH_MOUSE_LL, 
//原来是WH_MOUSE
                    MouseHookProcedure,
                    Marshal.GetHINSTANCE(
                        Assembly.GetExecutingAssembly().GetModules()[
0]),
                    
0);

//install hook
                hKeyboardHook = SetWindowsHookEx(
                    WH_KEYBOARD_LL, 
//原来是WH_KEYBORAD
                    KeyboardHookProcedure,
                    Marshal.GetHINSTANCE(
                    Assembly.GetExecutingAssembly().GetModules()[
0]),
                    
0);
 
  这样替换了之后,我们就可以实现全局钩子了,而且,不需要写DLL。看一下程序运行情况:



  下面是关于鼠标和键盘的两个Callback函数:

private int MouseHookProc(int nCode, int wParam, IntPtr lParam)

        {

            // if ok and someone listens to our events

            if ((nCode >= 0) && (OnMouseActivity != null))

            {

                //Marshall the data from callback.

                MouseLLHookStruct mouseHookStruct = (MouseLLHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseLLHookStruct));

 

                //detect button clicked

                MouseButtons button = MouseButtons.None;

                short mouseDelta = 0;

                switch (wParam)

                {

                    case WM_LBUTTONDOWN:

                        //case WM_LBUTTONUP:

                        //case WM_LBUTTONDBLCLK:

                        button = MouseButtons.Left;

                        break;

                    case WM_RBUTTONDOWN:

                        //case WM_RBUTTONUP:

                        //case WM_RBUTTONDBLCLK:

                        button = MouseButtons.Right;

                        break;

                    case WM_MOUSEWHEEL:

                        //If the message is WM_MOUSEWHEEL, the high-order word of mouseData member is the wheel delta.

                        //One wheel click is defined as WHEEL_DELTA, which is 120.

                        //(value >> 16) & 0xffff; retrieves the high-order word from the given 32-bit value

                        mouseDelta = (short)((mouseHookStruct.mouseData >> 16) & 0xffff);

                        //TODO: X BUTTONS (I havent them so was unable to test)

                        //If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP,

                        //or WM_NCXBUTTONDBLCLK, the high-order word specifies which X button was pressed or released,

                        //and the low-order word is reserved. This value can be one or more of the following values.

                        //Otherwise, mouseData is not used.

                        break;

                }

 

                //double clicks

                int clickCount = 0;

                if (button != MouseButtons.None)

                    if (wParam == WM_LBUTTONDBLCLK || wParam == WM_RBUTTONDBLCLK) clickCount = 2;

                    else clickCount = 1;

 

                //generate event

                 MouseEventArgs e = new MouseEventArgs(

                                                    button,

                                                    clickCount,

                                                    mouseHookStruct.pt.x,

                                                    mouseHookStruct.pt.y,

                                                    mouseDelta);

                //raise it

                OnMouseActivity(this, e);

            }

            //call next hook

            return CallNextHookEx(hMouseHook, nCode, wParam, lParam);

        }


private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
 
{
            
//indicates if any of underlaing events set e.Handled flag
            bool handled = false;
            
//it was ok and someone listens to events
            if ((nCode >= 0&& (KeyDown != null || KeyUp != null || KeyPress != null))
            
{
                
//read structure KeyboardHookStruct at lParam
                KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
                
//raise KeyDown
                if (KeyDown != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
                
{
                    Keys keyData 
= (Keys)MyKeyboardHookStruct.vkCode;
                    KeyEventArgs e 
= new KeyEventArgs(keyData);
                    KeyDown(
this, e);
                    handled 
= handled || e.Handled;
                }


                
// raise KeyPress
                if (KeyPress != null && wParam == WM_KEYDOWN)
                
{
                    
bool isDownShift = ((GetKeyState(VK_SHIFT) & 0x80== 0x80 ? true : false);
                    
bool isDownCapslock = (GetKeyState(VK_CAPITAL) != 0 ? true : false);

                    
byte[] keyState = new byte[256];
                    GetKeyboardState(keyState);
                    
byte[] inBuffer = new byte[2];
                    
if (ToAscii(MyKeyboardHookStruct.vkCode,
                              MyKeyboardHookStruct.scanCode,
                              keyState,
                              inBuffer,
                              MyKeyboardHookStruct.flags) 
== 1)
                    
{
                        
char key = (char)inBuffer[0];
                        
if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key)) key = Char.ToUpper(key);
                        KeyPressEventArgs e 
= new KeyPressEventArgs(key);
                        KeyPress(
this, e);
                        handled 
= handled || e.Handled;
                    }

                }


                
// raise KeyUp
                if (KeyUp != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
                
{
                    Keys keyData 
= (Keys)MyKeyboardHookStruct.vkCode;
                    KeyEventArgs e 
= new KeyEventArgs(keyData);
                    KeyUp(
this, e);
                    handled 
= handled || e.Handled;
                }


            }


            
//if event handled in application do not handoff to other listeners
            if (handled)
                
return 1;
            
else
                
return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
        }

 

 

分享到:
评论

相关推荐

    界面开发(c++ 、.net)

    比如,目前市场上很多界面库在绘制窗口标题栏的时候,去掉了窗口的WS_CAPTION属性, 导致GetClientRect、GetWindowRect方法失效,从而加大了界面开发和设计的难度,当然也导致不能完美支持SDI/MDI等界面框架。...

    hook(钩子)编程源码

    关于钩子(hook)编程的源码,方方面面都有介绍,各种钩子,全局钩子,鼠标钩子等等 关于钩子的原理,在本人博客有详细介绍: http://blog.cdsn.net/mingojiang

    键盘Hook可视化的控件 v1.0

    Hook(钩子)并不是一项很难的技术,但对于初学者来说还是一个不小的门槛。为此,我将键盘Hook做成了...2.你可以参考我的控件设计模式来设计自己的Hook控件,如键盘Hook。 黄晓斌 hxb_leiyuan2000@163.net QQ:478522325

    鼠标Hook可视化的控件

    2.你可以参考我的控件设计模式来设计自己的Hook控件,如键盘Hook。3.本来想写一个组件包的,其中包括各种Hook控件,以及读写端口的控件,以方便初学者的使用,可是要些论文,以后再说吧。 黄晓斌 hxb_leiyuan2000@...

    Visual_Studio.NET相关词汇中英翻译

    ActiveX Designer ActiveX 设计器 ActiveX Document Migration Wizard ActiveX 文档移植向导 ActiveX-enabled 支持 ActiveX 的 Add key/ Multiply key/ Substract key/ Devide key 加号键/ 乘号键/ 减号键/ 除号键 ...

    SpyWorks – 突破VB局限实现C++功能的工具库集

    · SpyWorks hook控件和子类控件(subclassing)的更新版本,支持Visual Studio .NET的最终版,包含相关的.NET Primary InterOp程序集。 · 支持从Visual Studio .NET程序集导出函数。 · 该更新版包含大量的样例 ...

    Python和js实现逆向之加密参数破解.zip

    资源包含文件:设计报告word+源码 部分网站的 url 构成中含有加密参数,这些参数的加密方法写在了 JavaScript 中,而 js 通常经过了压缩,混淆和加密;本项目通过 AJAX 断点,hook 方法先寻找到加密入口,其次通过 ...

    皮肤控件研究文档,破解后的库文件,皮肤设计工具使用教程

    皮肤控件研究文档,破解后的库文件,皮肤设计工具使用教程 皮肤控件 skin++ skincrafter SkinFeature IrisSkin 我共享的都是本人实际验证过的精品,有文档,破解后的库文件,皮肤设计工具使用教程, 1 软件界面 每...

    [原创]Rattail 老鼠尾巴 键盘鼠标记录器(底层钩子HOOK),支持行为推测分析功能

    至于这样设计软件做什么用的,我就不说了,请自行领会。不过大飞飞基于学习目的开发,希望大家不要用做不正当用途,感谢!有啥问题可以与我联系:hedda # Plusii.com 这里提供的是RAR制作的安装包, 也可以直接改为...

    SKINSE界面库3.1

    比如,目前市场上很多界面库在绘制窗口标题栏的时候,去掉了窗口的WS_CAPTION属性, 导致GetClientRect、GetWindowRect方法失效,从而加大了界面开发和设计的难度,当然也导致不能完美支持SDI/MDI等界面框架。...

    超市管理信息系统(数据库)源代码

    该 XPMenu.ocx 也是网上来的,很流行的HookMenu,但居然不支持MDI窗体(无法显示图标),实在令人失望。 这个代码完整的实现了 Office XP 风格界面,虽然许多地方都是模拟的,但往往最简单的方法就是最好的,反正...

    基于Cesium+VUE模拟实现火箭发射全过程效果组件,完整demo和源代码,代码未加密/未压缩,可直接调用运行

    基于Cesium+VUE模拟实现火箭发射全过程效果组件...文章描述:https://blog.csdn.net/qq_34205305/article/details/125582004 代码不易,略收小费,使用过程中如果有任何问题欢迎在文章下进行评论或者私信,百分百回复哦

    国内首家采用MS全新 MiniFilter架构的SEFS透明加密内核 V 2.0.0.1发布

    设计类: AutoCAD 2004 、圆方BtoCAD、等 &lt;br&gt; 4. ................... &lt;br&gt; &lt;br&gt;SEFS--透明加密内核 ============================================= 商业授权:sales@sefs.net Bug 报告:bug@...

    zxing.java源码解析-delphi-examples:delphi-例子

    hook api 、 com 接口和 delphi 对象方法 属性表控件 32 位位图  数据结构和事件系统  点九图  用于生成不同 delphi 版本的组件包 使用 THttpClient 的简单自动更新程序  一个 pascal 代码实现的类似 html5 ...

    Visual C++2010开发权威指南(共三部分).part1.rar

    4.1.3 设计对话框 150 4.2 创建与销毁对话框 153 4.2.1 模态对话框 153 4.2.2 非模式对话框 159 4.2.3 属性页对话框 163 4.3 消息对话框 173 4.4 通用对话框 175 4.4.1 文件打开对话框 176 4.4.2 文件保存对话框 178...

    亚信java笔试题-react-study:前端知识整合以及react基础demo

    ##设计模式 ##HTTPS ##JS全栈 ##Underscore.js ##文件上传 ##SWFUpload ##柯里化 ##jqGrid ##localStorage/sessionStorage ##Cookie ##onunload/onbeforeunload ##模板引擎 ##达夫设备 ##Promise ##Hook ##函数式...

    Reversing:逆向工程揭密

    12.2.2 .NET程序设计语言 428 12.2.3 通用类型系统 428 12.3 中间语言 429 12.3.1 求值堆栈 430 12.3.2 活动记录 430 12.3.3 IL指令 430 12.3.4 代码实例 433 12.4 反编译器 443 12.5 混淆器 444 12.5.1 重命名符号 ...

Global site tag (gtag.js) - Google Analytics