游戏修改器制作教程二:键盘鼠标钩子

原创 2015年11月20日 22:52:11

本教程面向有C\C++基础的人,最好还要懂一些Windows编程知识
代码一律用Visual Studio 2013编译,如果你还在用VC6请趁早丢掉它...
写这个教程只是为了让玩家更好地体验所爱的单机游戏,顺便学到些逆向知识,我不会用网络游戏做示范,请自重

本章内容主要是认识钩子(hook)

(微软的解释:)钩子(hook)是一种截获事件的机制,一个截获某种事件的函数叫做钩子过程(hook procedure),钩子过程可以处理它接收的每个事件,然后可以改变或取消这个事件

微软提供了API来实现一些钩子:

// 安装钩子,参数是钩子类型,钩子过程,钩子过程所在模块句柄,钩子的目标线程ID
// 如果dwThreadId是0则会安装全局钩子(截获所有进程所有线程的事件)
// 这时除了几种钩子类型,其他的必须把钩子过程写在DLL中,系统会把这个DLL注入到其他进程(本章不讲)
// 返回钩子句柄
HHOOK WINAPI SetWindowsHookEx(
  _In_ int       idHook,
  _In_ HOOKPROC  lpfn,
  _In_ HINSTANCE hMod,
  _In_ DWORD     dwThreadId
);
// 卸载钩子,参数是钩子句柄
BOOL WINAPI UnhookWindowsHookEx(
  _In_ HHOOK hhk
);
// 把事件传递给下一个钩子
LRESULT WINAPI CallNextHookEx(
  _In_opt_ HHOOK  hhk,
  _In_     int    nCode,
  _In_     WPARAM wParam,
  _In_     LPARAM lParam
);

更多关于钩子的详细说明请看MSDN:
Hooks Overview

本章会介绍低级键盘钩子(WH_KEYBOARD_LL)和低级鼠标钩子(WH_MOUSE_LL)

低级键盘钩子

低级键盘钩子可以截获准备进入某个线程输入队列的键盘输入消息(键盘按下、键盘弹起),它是少数不用把钩子过程写在DLL的全局钩子之一,而且它只能作为全局钩子
另外还有一个普通键盘钩子(WH_KEYBOARD),它和低级键盘钩子的区别是它截获准备被GetMessage或PeekMessage返回的键盘消息,而且如果要截获其他进程的消息你只能把它写到DLL里然后注入到其他进程
那么问题来了,既然低级键盘钩子的钩子过程没有注入到其他进程,它是怎么被调用的?这个的实现是系统发送个消息到安装钩子的线程实现调用钩子过程,这也意味着安装低级键盘钩子的线程必须有消息循环

完整的监听键盘输入的例程:

#include <Windows.h>

// 钩子句柄
HHOOK g_hHook;

// 钩子过程
LRESULT CALLBACK kbdProc(int code, WPARAM wParam, LPARAM lParam)
{
	if (code != HC_ACTION) // 不应该做处理
		return CallNextHookEx(g_hHook, code, wParam, lParam);

	PKBDLLHOOKSTRUCT param = (PKBDLLHOOKSTRUCT)lParam;

	// 按下ESC键退出
	if (param->vkCode == VK_ESCAPE)
		PostQuitMessage(0);

	// 取键名
	char keyName[200];
	GetKeyNameTextA(param->scanCode << 16, keyName, _countof(keyName));
	// 判断是按下还是弹起
	BOOL keyDown = (param->flags & (1 << 7)) == 0;

	printf("%s %s\n", keyName, keyDown ? "按下" : "弹起");

	// 把事件传递给下一个钩子
	return CallNextHookEx(g_hHook, code, wParam, lParam);
}

int _tmain(int argc, _TCHAR* argv[])
{
	printf("开始监听键盘,按下ESC键退出\n");

	// 安装低级键盘钩子
	// GetModuleHandle(NULL)会返回主模块(exe模块)句柄
	g_hHook = SetWindowsHookEx(WH_KEYBOARD_LL, kbdProc, GetModuleHandle(NULL), NULL);

	// 消息循环
	MSG msg;
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	// 卸载钩子
	UnhookWindowsHookEx(g_hHook);

	return (int)msg.wParam;
}

当然,别想用这个盗QQ,有点安全意识的软件都会有密码输入保护的

另外一个钩子WH_JOURNALRECORD也可以用来记录键盘和鼠标消息,但是它不能取消事件

屏蔽A键和把X键替换成Y键的例程:

把钩子过程改成下面这样就行了

	if (code != HC_ACTION) // 不应该做处理
		return CallNextHookEx(g_hHook, code, wParam, lParam);

	PKBDLLHOOKSTRUCT param = (PKBDLLHOOKSTRUCT)lParam;

	// 按下ESC键退出
	if (param->vkCode == VK_ESCAPE)
		PostQuitMessage(0);

	// 屏蔽A键
	if (param->vkCode == 'A')
	{
		// 返回一个非0值会取消这个事件
		return 1;
	}

	// 把X键替换成Y键
	if (param->vkCode == 'X')
	{
		static const int scanCode = MapVirtualKey('Y', MAPVK_VK_TO_VSC);
		BOOL keyDown = (param->flags & (1 << 7)) == 0;
		// 模拟输入Y键,这里我就偷懒用keybd_event了...
		keybd_event('Y', scanCode, keyDown ? 0 : KEYEVENTF_KEYUP, 0);
		// 取消这个事件
		return 1;
	}

	// 把事件传递给下一个钩子
	return CallNextHookEx(g_hHook, code, wParam, lParam);

运行后在记事本按下A键和X键试试

对于用DInput输入的程序用低级键盘钩子屏蔽按键是没用的,毕竟这个也只是处理消息,不过可以用来改键(虽然原按键也输入了!)(和SendInput一样,keybd_event指定了扫描码DInput程序也会响应)
想要更底层的屏蔽和真正的改键就用上一章提到的Interception吧(那可是内核级的),这样对所有的程序都有效了

低级鼠标钩子

低级鼠标钩子和低级键盘钩子一样,只不过它截获的是鼠标事件,也有个普通鼠标钩子(WH_MOUSE),和低级鼠标钩子的区别参考低级键盘钩子和普通键盘钩子的区别

完整的屏蔽鼠标移动和鼠标右键的例程:

#include <Windows.h>

// 钩子句柄
HHOOK g_hHook;

// 钩子过程
LRESULT CALLBACK mouseProc(int code, WPARAM wParam, LPARAM lParam)
{
	if (code != HC_ACTION) // 不应该做处理
		return CallNextHookEx(g_hHook, code, wParam, lParam);

	//PMSLLHOOKSTRUCT param = (PMSLLHOOKSTRUCT)lParam;

	// 按下鼠标左键退出
	if (wParam == WM_LBUTTONDOWN)
		PostQuitMessage(0);

	// 屏蔽鼠标移动、鼠标右键
	if (wParam == WM_MOUSEMOVE || wParam == WM_RBUTTONDOWN || wParam == WM_RBUTTONUP)
	{
		// 返回一个非0值会取消这个事件
		return 1;
	}

	// 把事件传递给下一个钩子
	return CallNextHookEx(g_hHook, code, wParam, lParam);
}

int _tmain(int argc, _TCHAR* argv[])
{
	printf("开始监听鼠标,按下鼠标左键退出\n");

	// 安装低级鼠标钩子
	// GetModuleHandle(NULL)会返回主模块(exe模块)句柄
	g_hHook = SetWindowsHookEx(WH_MOUSE_LL, mouseProc, GetModuleHandle(NULL), NULL);

	// 消息循环
	MSG msg;
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	// 卸载钩子
	UnhookWindowsHookEx(g_hHook);

	return (int)msg.wParam;
}


那么键盘鼠标钩子除了盗号外还有什么用呢?比如某些游戏里用热键没用的话可以用键盘钩子作为热键,另外大部分电子教室锁定学生键盘鼠标也是用了低级键盘钩子和低级鼠标钩子

本章内容只是为了认识钩子嘛,以后会讲到更强大的钩子,这也是游戏作弊器的一个重要机制

版权声明:本文为博主原创文章,转载请注明原作者。

VC++ Hook截取鼠标点击窗口消息的问题!全局钩子

VC++ Hook截取鼠标点击窗口消息的问题!全局钩子,高手进!悬赏分:0 - 提问时间: 2010年05月19日 06时20分我在做毕业设计,现在遇到一个问题,像求教高手:我想实现如下功能,当鼠标点...
  • taiq
  • taiq
  • 2010年12月23日 20:03
  • 9283

游戏修改器制作教程七:注入DLL的各种姿势

注入的代码就是目标进程的一部分了,可以直接用指针读写目标进程内存,还可以hook目标进程的函数...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

鼠标全局钩子

转自:http://www.tuicool.com/articles/BfAZna 有问题:在dllmain.h文件中加上extern HINSTANCE glhInstance;不然它总是找不...

游戏修改器制作教程⑨:修改D3D渲染

本章我们要实现hook游戏的渲染过程,把渲染自机换成播放bad apple(只是我看了别人的视频想自己做一个,没什么实际意义,但是可以说明怎么修改指定物体的渲染)...

JAVA模拟微信消息发送请求

JavaWeb模拟微信(网页版)发送消息,图片,文件到好友。PS:不是公众号,是好友之间,或者发送到群。1、发送文字消息到好友,或群。1、登录微信网页版,使用firebug抓取发送文字的请求:http...

游戏修改器制作教程一:键盘鼠标模拟

先从最简单的模拟操作讲起 模拟键盘鼠标有很多方法,我大体分为消息模拟、API模拟、驱动模拟 对于网页的话还可以用JavaScript模拟,虽然这不在本教程范围...

游戏修改器制作教程四:用API读写内存

上一章讲了用CE读写内存,本章讲如何自己编程实现 本文以制作东方辉针城修改器的实战讲解读写内存...

游戏修改器制作教程六:hook的各种姿势

在第二章介绍了hook机制,本章要自己实现hook,实现调用某个函数时我们能截获、修改、取消这次调用...

游戏修改器制作教程五:OllyDBG和其他调试工具

CE也不是专门用来调试的,本章将介绍几款调试工具,并且完善上一章的东方辉针城修改器...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:游戏修改器制作教程二:键盘鼠标钩子
举报原因:
原因补充:

(最多只允许输入30个字)