38.第二阶段x86游戏实战2-HOOK窗口消息机制(解决多开窗口句柄问题)

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!

本次游戏没法给

内容参考于:微尘网络安全

本人写的内容纯属胡编乱造,全都是合成造假,仅仅只是为了娱乐,请不要盲目相信。

工具下载:

链接:https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd=6tw3

提取码:6tw3

复制这段内容后打开百度网盘手机App,操作更方便哦

上一个内容:37.第二阶段x86游戏实战2-寻找万能按键call2

上一个内容找到了通过快捷键释放技能的call,并且根据逆向得到的内容从而写出了模拟调用的汇编代码,写的汇编代码也成功通过传不同的键盘键码释放了它对应的技能,本次开始把窗口的消息机制进行HOOK(HOOK就是拦截代码的意思)

怎样实现HOOK窗口的消息机制?

HOOK这个东西微软给提供了api,它有窗口HOOK、消息HOOK,所以一般直接使用微软的api就可以实现hook了

然后有一个主线程调用的知识点,就是之前我们写的dll文件注入到了游戏里,dll里面是一些通过逆向得到的功能call,比如寻路,这种功能调用一次两次的可能很稳定但长时间调用或挂机了一会它可能会导致游戏崩溃,这就用到了主线程调用这个概念,使用dll调用使用汇编调用功能call,这个调用过程是通过我们自己开的一个线程里做的,自己调用并没有把它们加入到消息机制里面,Windows应用它都有一个消息机制,不管鼠标移动还是键盘等一系列的操作,Windows都是把它们按着顺序压入到一个消息队列里面,然后再按照循序执行,这样不会有什么冲突也不会有什么问题,这时我们自己插入一个call,没有走Windows的消息队列,这时就会出问题了,这个call就可能会与系统的call有冲突,有冲突就会导致窗口(程序)崩溃。

上面写了这么多主线程调用和HOOK有什么关系?我们需要HOOK窗口消息HOOK消息队列HOOK消息机制从而实现把我们自己的消息也安排进这个消息队列里这是为什么HOOK的原因

开始之前需要一个东西,需要窗口句柄,窗口句柄可以通过spy++里的类名和标题获取,但是通过类名和标题获取的句柄,游戏(程序)多开的时候就有点难处理,有一个新的获取窗口句柄的方法,就是说游戏中或者说一个Windows窗口程序中它肯定有一个全局的变量存放这个窗口句柄了,所以通过spy++得到窗口句柄,如下图,当前窗口句柄,复制它,然后打开CE

然后使用CE搜索这个句柄,如下图,下图红框里的地址是绿色的,绿色的说明它已经是基址了

如下图可以查看,CE中已经是基址加偏移的方式了,通过这种方式获取句柄可以解决程序多开的问题

打开之前的项目,添加一个按钮

按钮的点击事件

本次通过对之前找的寻路代码加主线程调用为例,下方还没有写完(未写把寻路放到主线程里执行的逻辑,只写了hook主线程)

下图红框是hook主线程核心的代码,写了它就hook了主线程了

代码:

c++ 复制代码
// CM.cpp: 实现文件
//

#include "pch.h"
#include "tl.h"
#include "CM.h"
#include "afxdialogex.h"


// CM 对话框

IMPLEMENT_DYNAMIC(CM, CDialogEx)

HHOOK g_Hook返回;
HWND Call_获取窗口句柄()
{
	// 获取游戏存放的窗口句柄,通过CE搜索spy++的句柄找到的
	HWND hGame = (HWND)((DWORD)GetModuleHandleA("CEGUIBase.dll") + 0x251030);
	hGame = *(HWND*)hGame;
	return hGame;
}

LRESULT CALLBACK Call_主线程回调函数(int nCode, WPARAM wParam, LPARAM lparam)
{
	CWPSTRUCT *lpArg = (CWPSTRUCT*)lparam;//结构  hwnd message wParam lParam
	
	return CallNextHookEx(g_Hook返回, nCode, wParam, lparam);
}

DWORD Call_Hook主线程()
{
	HWND hGame = Call_获取窗口句柄();
	// 通过句柄获取窗口的线程id
	DWORD ndThreadId = GetWindowThreadProcessId(hGame, NULL);
	if (ndThreadId != 0)
	{
		// 注册窗口HOOK,SetWindowsHookEx是微软提供
		g_Hook返回 = SetWindowsHookEx(WH_CALLWNDPROC, Call_主线程回调函数, NULL, ndThreadId);
	}
	return 1;
}

CM::CM(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_DIALOG1, pParent)
	, edi_x(_T(""))
{

}

CM::~CM()
{
}

void CM::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Text(pDX, IDC_EDIT1, edi_x);
	DDX_Text(pDX, IDC_EDIT2, edi_y);
}


BEGIN_MESSAGE_MAP(CM, CDialogEx)
	ON_BN_CLICKED(IDC_BUTTON1, &CM::OnBnClickedButton1)
	ON_BN_CLICKED(IDC_BUTTON2, &CM::OnBnClickedButton2)
	ON_BN_CLICKED(IDC_BUTTON3, &CM::OnBnClickedButton3)
	ON_BN_CLICKED(IDC_BUTTON4, &CM::OnBnClickedButton4)
	ON_BN_CLICKED(IDC_BUTTON5, &CM::OnBnClickedButton5)
	ON_BN_CLICKED(IDC_BUTTON6, &CM::OnBnClickedButton6)
END_MESSAGE_MAP()


// CM 消息处理程序


void CM::OnBnClickedButton1()
{
	R_人物属性 a;
	a.初始化();
	Call_输出调试信息("人物信息:人物状态%d",a.状态);
}


void CM::OnBnClickedButton2()
{
	UpdateData(TRUE);
	CString str1 = edi_x;
	CString str2 = edi_y;
	// strtol((const char*)CW2A(str1.GetBuffer(0)), NULL, 10);把字符串转成int数字类型
	int x = strtol((const char*)CW2A(str1.GetBuffer(0)), NULL, 10);
	int y = strtol((const char*)CW2A(str2.GetBuffer(0)), NULL, 10);
	Call_xunlu(x, y);
}


void CM::OnBnClickedButton3()
{
	R_遍历背包 a;
	a.遍历背包();// 遍历背包
	CString str;
	str.Format(L"a数量 %d", a.d数量);
	AfxMessageBox(str);

	for (int i = 0; i < a.d数量; i++)
	{
		Call_输出调试信息("tl怀旧   背包信息 dwObject -------------%X----------------\r\n", a.列表[i].dwObject);
		Call_输出调试信息("tl怀旧   背包信息 名字:%s\r\n", a.列表[i].pName.c_str());
		Call_输出调试信息("tl怀旧   背包信息 使用等级:%d\r\n", a.列表[i].p使用等级);
		Call_输出调试信息("tl怀旧   背包信息 简介:%s\r\n", a.列表[i].简介.c_str());
		Call_输出调试信息("tl怀旧   背包信息 数量:%d\r\n", a.列表[i].p数量);


	}

}


void CM::OnBnClickedButton4()
{
	// TODO: 在此添加控件通知处理程序代码
	R_周围遍历 a;

	a.遍历最近怪物();// 让怪物重新排列
	for (int i = 0; i < a.d数量; i++)
	{
		Call_输出调试信息("人物信息:---------------------%s-----%x---------------------", a.列表[i].pName, a.列表[i].dwObject);
		Call_输出调试信息("人物信息:人物id:%x", a.列表[i].id);
		Call_输出调试信息("人物信息:人物X:%f 人物Y:%f", a.列表[i].fX, a.列表[i].fY);
		Call_输出调试信息("人物信息:人物类型:%x  人物距离:%f", a.列表[i].PType, a.列表[i].距离);


	}
}


void CM::OnBnClickedButton5()
{
	// TODO: 在此添加控件通知处理程序代码
	R_遍历技能 a;
	a.AsmGetMonsterData();// 遍历技能

	for (int i = 0; i < a.d数量; i++)
	{

		Call_输出调试信息("tl怀旧   技能信息 名字:---------------%s-----------------------\r\n", a.列表[i].pName.c_str());
		Call_输出调试信息("tl怀旧   技能信息 ID:%d\r\n", a.列表[i].pID);
			Call_输出调试信息("tl怀旧   技能信息 是否冷却:%s\r\n", a.列表[i].冷却.c_str());
			Call_输出调试信息("tl怀旧   技能信息 冷却ID:%x\r\n", a.列表[i].冷却ID);
		Call_输出调试信息("tl怀旧   技能信息 对象地址:%x\r\n", a.列表[i].dwObject);

	}
}


void CM::OnBnClickedButton6()
{
	Call_Hook主线程();
}

上方的代码不全,只有手写的代码

完整代码:

链接:https://pan.baidu.com/s/1W-JpUcGOWbSJmMdmtMzYZg?pwd=q9n5

提取码:q9n5

复制这段内容后打开百度网盘手机App,操作更方便哦


相关推荐
Mr-Apple2 分钟前
windows编译googletest框架搭配vscode调试
ide·windows·vscode
孤留光乩7 小时前
从零搭建纯前端飞机大战游戏(附源码)
前端·javascript·游戏·html·css3
王大队长7 小时前
Epic游戏使用mod
游戏
tealcwu9 小时前
【游戏设计原理】20 - 囚徒困境
游戏
慕羽★9 小时前
详细介绍如何使用rapidjson读取json文件
linux·c++·windows·json·file·param·rapidjson
这是我5810 小时前
C++打小怪游戏2
c++·游戏
sukalot10 小时前
windows C#-命名实参和可选实参(下)
windows·c#
软件开发技术深度爱好者12 小时前
使用Turtle库实现,鼠标左键绘制路径,用鼠标右键结束绘制,小海龟并沿路径移动
游戏
只抄15 小时前
Windows “高性能”模式既不高效,也不节能?
windows
bae-唯一17 小时前
扫雷游戏(基础版)
c++·游戏