纯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日

相关文章

  • CommunityToolkit.Mvvm8.1 viewmodel使用-旧式写法(2)

      本系列文章导航 https://www.cnblogs.com/aierong/p/17300066.html https://github.com/aierong/WpfDemo (自我Demo地址)     0.说明 CommunityToolkit.Mvvm8.1有一个重大更新的功能:源生成器功能,它极大简化我们的mvvm代码 但是本篇先总结一下原…

    C# 2023年4月18日
    00
  • C#实现的UDP收发请求工具类实例

    下面为您详细讲解如何实现“C#实现的UDP收发请求工具类实例”。 什么是UDP? UDP是一种无连接的传输协议,它不保证数据传输的可靠性,但是在实时传输和流媒体等领域得到了广泛应用。通过UDP传输数据时,数据包不可靠地从源端发送到目的地,不会进行确认、重传和拥塞控制等。 C#中的UDP实现 C#中提供了Socket类,可以用于创建UDP套接字和进行数据的收发…

    C# 2023年6月6日
    00
  • .Net行为型设计模式之中介者模式(Mediator)

    .Net行为型设计模式之中介者模式(Mediator) 中介者模式是一种行为型设计模式,它的目的是减少对象之间的耦合度,增强对象之间的协作性,从而提高整个系统的灵活性和可维护性。 在中介者模式中,对象之间的通信都是通过中介者进行的,而不是直接相互引用。这样一来,系统中的每个对象都只需要跟中介者通信,而不用关心其他对象的存在,使得系统更加松耦合,也更加容易扩展…

    C# 2023年5月31日
    00
  • C#实现如何使用短信平台自动通知用户实例

    C#实现使用短信平台自动通知用户 简介 短信通知是现在很多网站或应用程序都采用的一种通知方式,以及提供给客户服务的一种方式。本文将讲解如何使用C#实现自动向用户发送短信通知。 步骤 选择短信平台 首先需要选择一家短信平台进行合作,目前市面上主流的短信平台有阿里云短信、腾讯云短信、云之讯等,选择平台需考虑到短信发送成功率、价格等相关因素。 注册并获取短信API…

    C# 2023年6月6日
    00
  • 如何使用正则表达式判断邮箱(以C#为例)

    正则表达式是一种强大的匹配工具,在C#中使用正则表达式可以很方便地判断邮件地址的有效性。下面是判断邮箱的完整攻略: 正则表达式的语法 要想使用正则表达式来判断邮箱,需要掌握基本的正则表达式语法。以下是一些常用的正则表达式符号: ^ : 匹配字符串的开始位置。 $ : 匹配字符串的结束位置。 [] : 匹配方括号中出现的任意一个字符。 * : 匹配前面的字符零…

    C# 2023年6月3日
    00
  • asp.net的加密解密技巧

    ASP.NET提供多种加密解密技巧,以下是完整攻略: 1. 加密解密技巧的用途 在网站应用开发过程中,为了保护关键数据的安全,必须采取加密措施,确保网站数据的机密性和完整性。ASP.NET提供了一系列加密技巧,可以对网站数据进行加密和解密,可以提高网站数据的安全性。 2. ASP.NET加密解密库 ASP.NET提供了内置的加密解密库,包括System.Se…

    C# 2023年6月3日
    00
  • C#定时器实现自动执行的方法

    下面来详细讲解一下C#定时器实现自动执行的方法。 一、什么是定时器 在C#中,定时器是一种常用的机制,也就是周期性执行某个指定代码,定时器通常用于需要周期性执行某些操作的场景,例如轮询某个接口获取数据、定时备份数据、定时刷新界面等。在C#中,常用的定时器包括System.Timers.Timer、System.Threading.Timer、System.W…

    C# 2023年6月6日
    00
  • 使用源链接对ASP.NET Core源代码进行调试

    使用源链接对ASP.NET Core源代码进行调试 在ASP.NET Core应用程序中,源代码调试是一项非常重要的任务,它可以帮助您跟踪应用程序的运行情况并诊断问题。在本攻略中,我们将详细讲解如何使用源链接对ASP.NET Core源代码进行调试,并提供两个示例说明。 步骤一:启用源链接 要使用源链接对ASP.NET Core源代码进行调试,您需要在应用程…

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