22.第二阶段x64游戏实战-分析周围对象类型

发布于:2025-05-11 ⋅ 阅读:(19) ⋅ 点赞:(0)

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

本次游戏没法给

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

上一个内容:21.第二阶段x64游戏实战-分析采集物偏移

上一个内容里发现采集物的名字通过我们的列表展示出来是空的,然后又去找了采集物名字的偏移,这里就有一个问题,现在名字的偏移有两个npc(包含我们的角色、附近玩家、游戏中的npc)是一个偏移,采集物名字又是另外的偏移,什么时候用采集物的偏移什么时候用npc的偏移?游戏中它自身也会有这个问题,所以游戏中它肯定是有一个对象(对象是一个抽象的概念它指的可以是玩家、附近玩家、游戏中的npc、采集物等,它可以指任意一个东西,当前说的对象指的是玩家、附近玩家、游戏中的npc、采集物)类型,比如1表示我们的角色、2表示的是附近玩家、3表示游戏中的npc、4表示采集物等这样的数据,本次就来找这个类型是什么,找到类型之后,就可以通过类型判断什么时候用什么偏移了。

开始找类型,首先如下图红框,来到上一个内容得到采集物名字的位置

如下图红框,一设置断点它就会断下来,下图红框位置是采集物的名字,为什么会断下来?因为我的角色里采集物很近,游戏中访问采集物名字了

如下图,人物就在采集物旁边

接下来移动我们的角色,让它远离采集物,移动到采集物在地图上看不到了为止,如下图让角色远离采集物之后再次设置断点它就不会断下来了,当前位置前面的代码肯定有一行判断了类型,接下来就开始找远离了采集物在什么位置设置断点它还会断下来,为了防止有其它问题在开始之前记得把我们之前写的读取附近npc代码关闭

就算找在什么位置断下来也是有技巧的,下图rsi在上一个内容中看到的它是采集物对象,然后就找rsi在哪赋值的,通过找它来找断点位置

如下图通过往上滑看到还有位置读取了rsi+0x150位置,给他设置断点它也不会断,继续往上滑

通过不断的往上滑和设置断点,发现下图位置设置断点之后会断下来

然后在下图位置设置断点不会断下来

当移动到有矿石的位置它才会断下来

它断不断取决于下图红框位置的代码 test eax,eax,test和je配合意思是值是0的时候je会跳转

下图置位的意思是赋值,也就是把zf标识设置成1

然后eax的值来自于下图红框call,所以就要进入这个call

设置断点

取消断点

然后按F7进入call

代码的分析,大体就是判断rdx和r8是不是相等,rdx和r8应该就是类型了

如下图按减号(-号)回到上一层,可以看到r8来自于一个基址,rdx来自于rax

r8的值是一个字符串这个字符串Resource应该就是采集物的类型了,Resource中文是资源的意思

然后找一下rax的值哪来的,如下图红框,rax的值来自于call rax+0x70这个函数

通过分析下图红框的三行代码,可以知道这个应该rax+0x70是一个对象的虚函数(下面就写虚函数在内存中的样子和介绍)

设置断点

取消断点

按F7进入call rax + 0x70,如下图它就一行代码

然后跳转到 0x00007FF6BE5253E0 这个地址 MouseTarget中文意思鼠标目标

然后移动角色到采集物位置,继续在下图红框位置设置断点,这个游戏如果不移动到采集物附近,rax的值不会变

如下图断点查看当前rax的值

如下图打开我们的遍历周围列表,可以发现rcx是对象地址

通过上面的分析知道了,对象继承了一个通用类,虚函数就是父类中的函数,这是C++中的概念,不了解C++只要记得上面三行的写法就是调用虚函数(见多了就记住了),虚函数有多个对象首地址存放的就是虚函数列表,rax+0x70虚函数用来得到当前对象的类型,下面手动找虚函数,查看它的类型,下图红框是一个怪物的对象

跳转到对象位置

然后在内存窗口中跳转过去

然后右击选择地址

然后偏移0x70位置

右击选择在反汇编中转到指定QWORD

如下图跳转之后

然后复制 lea rax, ds:[0x00007FF6BE524FC8]中 0x00007FF6BE524FC8这个地址,这个怪物的类型是PlayerNPC

再看一个我们自己 PlayerMySelf,MySelf中文我自己的意思

现在就找到类型了,然后开始计算 lea rax, ds:[0x00007FF6BE524EA8] 里面的0x00007FF6BE524EA8怎么取,去它要用到下图红框的两个东西,下一行代码的地址和当前代码+0x3位置

为什么是当前代码+0x3位置,如下图

计算公式 A1 09 82 00 这是小端序存储用的时候要反着写(我们自己用的Windows系统一般都是小端序存储)

总结:

现在我们要取类型的话,首先获取对象,然后获取虚函数表,然后得到0x70位置的虚函数,然后取加0x3位置的数据就得到了A1 09 82 00,然后在取+0x7位置也就是下一行代码的地址,然后让它俩相加就得到了类型

开始写代码,下图红框位置是列表显示类型的代码

然后获取名字的代码

VDataStu  GameData::TraverseBN(QWORD point) {

	// [[[[ReadDword64(B_number + 8) + 0x10]+ 0x28] + 0x1B0] + 0x18] + 0x8
	/**
		判断是否选中(或者说找到目标的标记)
	*/
	if (!ReadByte(point + 0x19)) {
		Role_Stu Rstu;
		Rstu.m_Objadr = ReadDword64(point + 0x28);// 获取树中的数据
		/*Rstu.m_ID = ReadInt(Rstu.m_Objadr + 0x44);*/

		/**
			ReadDword64(Rstu.m_Objadr) + 0x70) 得到虚函数
			ReadDword64(ReadDword64(Rstu.m_Objadr) + 0x70) + 3) 得到虚函数+0x3位置的数据,也就是A1 09 82 00
			ReadDword64(ReadDword64(Rstu.m_Objadr) + 0x70) + 7) 这个是得到下一行代码
		*/
		QWORD address = ReadDword64(ReadDword(ReadDword64(ReadDword64(Rstu.m_Objadr) + 0x70) + 3) + ReadDword64(ReadDword64(Rstu.m_Objadr) + 0x70) + 7);
		Rstu.type_name = ReadStrA((char*)address);

		QWORD addr = ReadDword64(ReadDword64(Rstu.m_Objadr + 0x1b0) + 0x18);
		Rstu.m_HP.ptr = ReadFloat(addr + 8) * 100;
		// 判断 type_name字符串是不是以Resource结尾,如果是就说明当前是采集物
		if (Rstu.type_name.find("Resource") != string::npos)
			// 得到采集物名字
			Rstu.m_Name = ReadStrA((char*)(ReadDword64(ReadDword64(Rstu.m_Objadr + 0x150) + 0x8)));
		else
			Rstu.m_Name = ReadStrA((char*)(addr + 0x30));

		Rstu.fPos.x = ReadFloat(Rstu.m_Objadr + 0x5c);
		Rstu.fPos.z = ReadFloat(Rstu.m_Objadr + 0x60);
		Rstu.fPos.y = ReadFloat(Rstu.m_Objadr + 0x64);


		m_Around.m_data.push_back(Rstu);
		TraverseBN(ReadDword64(point));// 遍历左边的树
		TraverseBN(ReadDword64(point + 0x10));// 遍历右边的树
	}
	return m_Around;
}

效果图:

 


img


网站公告

今日签到

点亮在社区的每一天
去签到