纯C#实现Hook功能详解

C#实现Hook功能详解

什么是Hook

在计算机编程领域,Hook是指拦截某个操作,加入自定义的操作或者修改已有操作的过程。

Hook的种类

Windows系统中可用的Hook种类有三种:

  1. 全局钩子(Global Hook)

全局钩子会影响整个操作系统,可以拦截鼠标、键盘、消息、Shell等等所有操作,需要管理员权限安装和使用,且有一定的性能损失。

  1. 线程钩子(Thread Hook)

线程钩子只会钩住单个线程,不会影响整个操作系统,可以拦截鼠标、键盘等操作。

  1. 应用程序钩子(Application Hook)

应用程序钩子只会钩住单个应用程序,通过DLL注入的方式实现。可拦截路径、文件等。

C#实现Hook

C#语言可以通过托管代码结合C++ dll的方式实现Hook。

  1. 创建一个Class Library项目,将Hook功能封装在其中

  2. 在该项目中添加一个C++ CLR Class

在项目中添加一个类,选择C++/CLR语言,作为Hook操作的实现。在其中定义好相关的钩子事件,如键盘事件等。

  1. 在Hook类中增加Hook函数

Hook函数主要实现了Hook种类、DLL注入等。

  1. 在Hook类中增加钩子事件

定义钩子事件,该事件会在接收到需要Hook的操作时被触发。

  1. 在Hook类中增加处理函数

处理函数主要实现了Hook收到事件时需要采取的操作,如输出日志等。

示例1:全局钩子

下面是一个全局钩子示例代码:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace GlobalHook
{
    public class GlobalKeyboardHook : IDisposable
    {
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook, HookCallBack lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        delegate IntPtr HookCallBack(int nCode, IntPtr wParam, IntPtr lParam);

        const int WH_KEYBOARD_LL = 13;
        const int WM_KEYDOWN = 0x100;

        private IntPtr hookId = IntPtr.Zero;
        private HookCallBack hookProc;
        private EventHandler<KeyEventArgs> keyPressed;
        private bool disposed = false;

        public GlobalKeyboardHook()
        {
            hookProc = new HookCallBack(HookCallback);
            hookId = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, IntPtr.Zero, 0);
            keyPressed = new EventHandler<KeyEventArgs>(OnKeyPressed);
        }

        public event EventHandler<KeyEventArgs> KeyPressed
        {
            add { keyPressed += value; }
            remove { keyPressed -= value; }
        }

        protected virtual void OnKeyPressed(object sender, KeyEventArgs e)
        {
            if (keyPressed != null)
            {
                keyPressed(this, e);
            }
        }

        private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
            {
                int vkCode = Marshal.ReadInt32(lParam);
                OnKeyPressed(this, new KeyEventArgs((Keys)vkCode));
            }
            return CallNextHookEx(hookId, nCode, wParam, lParam);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    if (keyPressed != null)
                    {
                        foreach (EventHandler<KeyEventArgs> handler in keyPressed.GetInvocationList())
                        {
                            keyPressed -= handler;
                        }
                    }
                }
                UnhookWindowsHookEx(hookId);
                disposed = true;
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        ~GlobalKeyboardHook()
        {
            Dispose(false);
        }

    }
}

示例2:线程钩子

下面是一个线程钩子示例代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ThreadHookDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        [DllImport("user32.dll")]
        public static extern int SetWindowsHookEx(int hookType, HookProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll")]
        public static extern int CallNextHookEx(int hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll")]
        public static extern int UnhookWindowsHookEx(int hhk);

        public static int WH_MOUSE_LL = 14;
        public static int WH_KEYBOARD_LL = 13;

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

        IntPtr hookId;
        HookProc hook = MouseHookProc;

        private void button1_Click(object sender, EventArgs e)
        {
            if (hookId == IntPtr.Zero)
            {
                IntPtr hInstance = Marshal.GetHINSTANCE(this.GetType().Module);
                hookId = (IntPtr)SetWindowsHookEx(WH_MOUSE_LL, hook, hInstance, 0);
                if(hookId == IntPtr.Zero)
                {
                    MessageBox.Show("Failed to hook the mouse");
                }
                else
                {
                    button1.Text = "Unhook";
                }
            }
            else
            {
                UnhookWindowsHookEx((int)hookId);
                hookId = IntPtr.Zero;
                button1.Text = "Hook";
            }
        }

        private static int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode == 0)
            {
                int x = Marshal.ReadInt32(lParam);
                int y = Marshal.ReadInt32(lParam + 4);

                Debug.Print("X: {0}, Y: {1}", x, y);
            }
            return CallNextHookEx(0, nCode, wParam, lParam);
        }
    }
}

总结

Hook是一种非常重要的技术,可以拦截并修改操作系统的行为,改善用户的操作体验。通过上述示例代码,我们可以更深入理解Hook的实现方法,同时也可以据此开发类似的功能。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:纯C#实现Hook功能详解 - Python技术站

(0)
上一篇 2023年6月6日
下一篇 2023年6月6日

相关文章

  • c# 实现IComparable、IComparer接口、Comparer类的详解

    C#实现IComparable、IComparer接口、Comparer类的详解 IComparable 接口 System.IComparable 接口定义了比较对象的方法,该方法将对象与相同类的另一个对象进行比较。如果对象 ‘A’ 应该排在对象 ‘B’ 之前,则该方法返回负数值;如果对象 ‘A’ 应该排在对象 ‘B’ 之后,则返回正数值;如果对象 ‘A’…

    C# 2023年5月15日
    00
  • 详解ASP.Net Core 中如何借助CSRedis实现一个安全高效的分布式锁

    详解ASP.Net Core 中如何借助CSRedis实现一个安全高效的分布式锁 在ASP.Net Core应用程序中,分布式锁是一项非常重要的任务,它可以帮助您避免并发问题和数据竞争。CSRedis是一种流行的Redis客户端,它可以帮助我们实现分布式锁。在本攻略中,我们将详细讲解如何借助CSRedis实现一个安全高效的分布式锁,并提供两个示例说明。 步骤…

    C# 2023年5月17日
    00
  • C#连接MySql数据库的方法

    连接MySql数据库需要用到MySql.Data.dll和System.Configuration.dll这两个库,接下来将通过以下几个步骤讲解C#连接MySql数据库的方法: 1. 引用相关库 在项目中引入MySql.Data.dll和System.Configuration.dll这两个库。 2. 建立数据库连接字符串 数据库连接字符串包括数据库名称、服…

    C# 2023年5月15日
    00
  • ASP.NET Core中的wwwroot文件夹

    ASP.NET Core中的wwwroot文件夹是用于存放Web应用程序静态资源的目录。该目录中的文件可被直接发布到Web服务器上,比如图片、JavaScript、CSS、HTML文件等,这些文件可以通过路径直接访问,而不需要经过服务器端的处理。下面我们来详细讲解一下wwwroot文件夹。 如何创建wwwroot文件夹? 在使用ASP.NET Core建立W…

    C# 2023年6月3日
    00
  • C#实现调用迅雷下载的方法

    让我们来分步骤地讲解如何使用C#实现调用迅雷下载的方法。 步骤一:了解调用迅雷协议 迅雷软件是支持HTTP、FTP和ED2K等协议的下载工具,而它还提供了一套自己的迅雷协议,可以通过这个协议实现与迅雷软件的交互。 在C#中,我们可以使用以下格式的URL来调用迅雷下载的方法: thunder://QUFmdHA6Ly9kZG5zLmdvb2dsZS5jb20v…

    C# 2023年5月15日
    00
  • 如何在C#中集成Lua脚本

    如何在C#中集成Lua脚本 Lua是一种轻量级脚本语言,它被广泛应用于游戏编程、嵌入式系统和工业自动化等领域。在C#中集成Lua脚本可以使开发者更加灵活地扩展应用程序的功能。下面是详细的攻略: 步骤一:下载并安装Lua库 在http://www.lua.org/download.html官网上下载适合您系统的Lua库并解压到本地目录,例如C:\Lua。 步骤…

    C# 2023年5月15日
    00
  • C# TextWriter.Close – 关闭文本编写器

    C#中的TextWriter类是一个抽象类,用于向文本或流中写入字符。 Close() 方法是 TextWriter 类的一个实例方法,用于关闭当前 writer 对象并释放与此对象关联的所有系统资源(比如内存和句柄)。 以下是 TextWriter.Close 方法的使用方法: public virtual void Close (); 在调用 Close…

    C# 2023年4月19日
    00
  • ASP.NET 程序员都非常有用的85个工具

    ASP.NET程序员都非常有用的85个工具 作为ASP.NET程序员,我们需要使用各种工具来提高我们的工作效率和代码质量。在本文中,我们将介绍85个非常有用的ASP.NET工具,这些工具可以帮助我们更好地开发和维护ASP.NET应用程序。 1. 开发工具 以下是一些非常有用的ASP.NET开发工具: 1.1 Visual Studio Visual Stud…

    C# 2023年5月15日
    00
合作推广
合作推广
分享本页
返回顶部