抛砖引玉 - hook的小例子

前阵子家里的笔记本出了点问题,就是键盘上的ESC键被卡住了,一直处理按下的状态,导致一系列问题(比如QQ窗口一开就提示是否关闭窗口等等)。N多不爽之后,决定写个程序暂时屏蔽掉ESC键。前阵子盗梦空间这么火,程序就叫KeyboardInception吧。哈哈。

简单地说,就是让程序捕获所有ESC键按下的事件,然后直接丢掉,这里需要用到windows下的hook技术,注意是hook,不是hooker(邪恶了:))。

Windows系统在运行过程中会产生各种各样的消息,hook,中文翻译为钩子,就是这个平台下的一种技术,它可以捕获指定的消息,通过回调函数,对消息进行响应,或是修改消息,甚至是拦截消息的传递。

应用程序使用钩子,需要把钩子安装到系统中,使用完成之后还需要进行卸载。系统中可能同时安装了很多很多很多的钩子,形成一个钩子链,最近安装的钩子在链的前端,可以获得优先的控制权。

安装钩子:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr SetWindowsHookEx(int hookId, HookProc pfnHook, IntPtr hInst, int threadId);

可参考:http://msdn.microsoft.com/en-us/library/ms644990(VS.85).aspx

卸载钩子:
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
internal static extern bool UnhookWindowsHookEx(IntPtr hHook);

把消息传递给钩子链的下一个钩子:
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
internal static extern int CallNextHookEx(IntPtr hHook, int code, IntPtr wParam, IntPtr lParam);

废话少说,直接贴代码了。

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;

namespace KeyboardInception
{
    public static class HookHelper
    {
        #region Intercept Esc Key

        private static IntPtr _hHookInterceptEscKey = IntPtr.Zero;
        private static GCHandle _hInterceptEscKeyProc;

        private static bool _interceptEsc;
        public static bool InterceptEsc
        {
            get
            {
                return _interceptEsc;
            }

            set
            {
                _interceptEsc = value;
            }
        }

        private static bool _interceptAll;
        public static bool InterceptAll
        {
            get
            {
                return _interceptAll;
            }

            set
            {
                _interceptAll = value;
            }
        }

        public static bool HookInterceptEscKey()
        {
            //
            if (_hHookInterceptEscKey != IntPtr.Zero) UnhookInterceptEscKey();

            //
            HookProc hookProc = new HookProc(KeyboardCallback);
            _hInterceptEscKeyProc = GCHandle.Alloc(hookProc);

            _hHookInterceptEscKey = SetWindowsHookEx(WH_KEYBOARD, hookProc, GetModuleHandle("KERNEL32.dll"), 0);
            
            //
            return _hHookInterceptEscKey != IntPtr.Zero;
        }

        public static void UnhookInterceptEscKey()
        {
            try
            {
                if (_hHookInterceptEscKey != IntPtr.Zero)
                {
                    UnhookWindowsHookEx(_hHookInterceptEscKey);
                    _hHookInterceptEscKey = IntPtr.Zero;
                    _hInterceptEscKeyProc.Free();
                }
            }
            catch
            {
                // ...
            }
        }

        private static int KeyboardCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (_interceptEsc)
            {
                KBDLLHOOKSTRUCT keyBoardHookStruct = new KBDLLHOOKSTRUCT();
                CopyMemory(ref keyBoardHookStruct, lParam, 20);

                if (keyBoardHookStruct.vkCode == 27) return 1;
            }

            if (_interceptAll)
            {
                return 1;
            }

            return CallNextHookEx(_hHookInterceptEscKey, nCode, wParam, lParam);
        }

        #endregion

        #region PInvoke

        #region Const

        private const int WH_KEYBOARD = 13;

        #endregion

        #region Nested type

        internal delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);

        [StructLayout(LayoutKind.Sequential)]
        public struct KBDLLHOOKSTRUCT
        {
            public int vkCode;
            public int scanCode;
            public int flags;
            public int time;
            public int dwExtraInfo;
        }

        #endregion

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        internal static extern IntPtr SetWindowsHookEx(int hookId, HookProc pfnHook, IntPtr hInst, int threadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        internal static extern bool UnhookWindowsHookEx(IntPtr hHook);

        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        internal static extern int CallNextHookEx(IntPtr hHook, int code, IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        internal static extern IntPtr GetModuleHandle(string lpModuleName);

        [DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory")]
        internal static extern void CopyMemory(ref KBDLLHOOKSTRUCT source, IntPtr destination, int length);

        #endregion
    }
}


本例子的源代码下载,编译及运行需安装.net framework2.0。
http://download.csdn.net/source/3309962

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一个完整的hook程序的例子 一、客户端 程序命名为Client。监视系统的运行,如发现系统中有“记事本”进程(notepad.exe)或者“计算器”进程(calc.exe),立即杀死(kill)该进程,并将该事件写入数据库;定期进行检查,每间隔1分钟,检查数据库,将尚未上传的事件记录上传至服务器端。 1、目标运行环境为Windows 2000操作系统。 2、程序请设计为系统服务。 3、程序需具备抗攻击能力,包括反删除、对抗强制终止进程等功能。 (1)保持程序的持续运行,防止其他程序强行终止当前程序的运行; (2)保护事件数据库和主执行文件不被删除; (3)如发现异常(进程被终止、文件被删除等),立即强制重新载入/运行程序; (4)如连续3次发现异常,守护进程强制重新启动操作系统;重启系统后保证程序正常载入并运行。 (A)为实现以上功能,程序不限于以EXE形式实现,可根据需要自行决定实现形式。 (B)以上功能均在Windows 2000正常运行环境、Administrator权限下实现,无需考虑Windows安全模式或者权限等问题。 4、请使用简单桌面数据库,如Access、xBase等文件型数据库。 5、每次生成的事件至少包含2部分信息:事件发生时间和事件处理对象。 数据库中以表tEvent存储事件数据。tEvent表至少包含两个字段: (1)EventTime字段:时间/日期类型。记录事件发生的时间。 (2)EventTarget字段:字符类型。记录事件中所Kill的对象。需要考虑的对象有记事本进程和计算器进程。 如果需要其他表或者字段,可根据需要自行添加。 6、网络数据传输格式自定。传输的具体内容和格式请根据需要自行决定,不做具体要求。客户端网络需与服务器端网络配合工作。 7、所用开发语言与集成开发环境不限,可自行选择。 8、对于数据库连接方式,请根据需要自行选择。 二、服务器端 程序命名为Server。监听网络,一旦有客户端上传数据,立即从中提取事件信息,并在用户界面中以列表方式加以显示。 1、目标运行环境为Windows 2000操作系统。 2、程序请设计为普通Windows 2000 GUI应用程序。在用户界面中至少需包含一个事件信息列表,该列表中至少包含3部分信息:事件发生时间、事件处理对象和事件来源。 (1)事件发生时间:同客户端事件发生时间。 (2)事件处理对象:同客户端事件处理对象。 (3)事件来源:上传当前事件的客户端机器的IP地址。 3、网络数据传输格式自定;与客户端配合工作。 4、所用开发语言与集成开发环境不限,可自行选择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值