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,操作更方便哦


相关推荐
Yang.992 小时前
基于Windows系统用C++做一个点名工具
c++·windows·sql·visual studio code·sqlite3
我不瘦但很逗2 小时前
Windows下使用DBeaver连接云数据库(MySQL)
数据库·windows
ashane13144 小时前
Java list
java·windows·list
万里沧海寄云帆4 小时前
Word 插入分节符页码更新问题
windows·microsoft·word
dot.Net安全矩阵5 小时前
.NET 通过模块和驱动收集本地EDR的工具
windows·安全·web安全·.net·交互
编程修仙6 小时前
Collections工具类
linux·windows·python
程序员小羊!8 小时前
高级 SQL 技巧讲解
windows
九州ip动态9 小时前
模拟器多开限制ip,如何设置单窗口单ip,每个窗口ip不同
tcp/ip·游戏·媒体
St_Ludwig9 小时前
C语言 蓝桥杯某例题解决方案(查找完数)
c语言·c++·后端·算法·游戏·蓝桥杯
xiangshangdemayi9 小时前
Windows环境GeoServer打包Docker极速入门
windows·docker·容器·geoserver·打包·数据挂载