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

原创 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;
}


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

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

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

相关文章推荐

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

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

c++中dll介绍(详细)

参考出处:http://www.cnblogs.com/flyingfish/archive/2007/03/28/691775.html 天极网 深入浅出Visual C++动态链接库(Dll)...

VS2010中 C++创建DLL图解

一、DLL的创建  创建项目: Win32->Win32项目,名称:MyDLL 选择DLL (D) ->完成. 1、新建头文件testdll.h testdll.h代码如下: #...

C++ DLL导出类

在公司使用C++ 做开发,公司的大拿搭了一个C++的跨平台开发框架。在C++开发领域我还是个新手,有很多知识要学,比如Dll库的开发。    参考了很多这方面的资料,对DLL有一个基本全面的了解。有一...

c++显式加载dll并使用DLL的类

转载自:  http://blog.163.com/tianjunqiang666@126/blog/static/8725911920121064573594/ 首先需要强调,当使用某...

VS2013 c++ 生成和调用DLL动态链接库

创建动态库方法: 创建动态库是生成 .dll .lib 两个个文件 文件 -> 新建 -> 项目 -> win32控制台应用程序 项目名称:DLLGenerator 应用程序类型:DLL...

游戏修改器制作教程三:内存与Cheat Engine

计算机程序所有的变量、代码都是储存在内存里的,包括游戏里那些HP、MP、金钱等,那么只要能修改内存就能自由改变玩家的HP、金钱了(当然对于网游是没用的,这些数据都储存在服务器,客户端里的只是一个副本)...

利用C++制作dll并调用dll

Abstract:本文讲解如何利用c++制作dll并调用dll,用一个简单的加法函数来作为演示,并给出图形界面。1. 打开vs(我用的是vs2010),然后点击文件—>文件—>新建—>项目,选择Win...

SQL 优化

原文地址:http://www.cnblogs.com/kivenhou/archive/2010/10/06/1844856.html具体要注意的: 1.应尽量避免在 where 子句中对字段进行 ...

JAVA调用动态链接库DLL之JNative学习

JAVA调用动态链接库DLL的方法有:JNI(Java Native Interface),JInvoke,JNative(Java to native interface),JNI是JAVA自身提供...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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