FPS网络游戏自动瞄准漏洞分析以及实现

来源:互联网 编辑:wan玩得好手游小编更新:2024-10-29 12:14:34 人气:

0x0. 前言


来到论坛已经有一段时间了,目前大三学生,乐于分享知识,看到论坛招聘讲师的帖子,于是想发点文字,分享知识,不知道能不能申请精华。


新年刚刚过去,不知道大家亲戚走没走完,新的一年里,祝大家财源广进,身体健康,万事如意,一切都会好起来的!



0x1. 了解FPS游戏自瞄漏洞


经常玩游戏的朋友,应该知道FPS游戏,例如:穿越火线,逆战等等,他们的特点就是以第一人称视角进行操作人物,屏幕中间会有一个准星,通过准星瞄准敌人进行攻击以达到击杀效果和游戏体验。


由于FPS游戏的特殊游戏体验,所以使得很多不法分子利用逆向知识开发了很多自动瞄准的工具,破坏了游戏平衡。具体的原理如下:


1.找到存放鼠标准星的坐标基地址;

2.找到人物数组基地址;

3.找到人物数组下人物的相关属性偏移:血量,名字,坐标,阵营等;

4.通过阵营判断是否为敌人,通过血量判断是否死亡,利用算法将自己的准星坐标修改为敌人所处的位置,实现自动瞄准。



0x2. 利用某FPS网络游戏进行分析


用到工具:CE,OllyDbg


首先,我们分析了解一下FPS鼠标准星的知识,并且找出他的内存地址:


搜索前,我们要理清思路,那就是如何去定位鼠标的坐标,怎么定位比较方便。因为游戏分为鼠标X和鼠标Y两种坐标,鼠标X即左右的坐标,鼠标Y为上下坐标,由于左右坐标在游戏中转一圈无法确定坐标数据是否增大还是减小,所以我们通常分析鼠标的Y,即上下坐标。


针对鼠标Y坐标变动的情况分析:


无鼠标准星特殊加密:


1.向上移动准星坐标增大,向下移动准星坐标减小;


2. 向上移动准星坐标减小,向下移动准星坐标增大。


鼠标准星特殊加密:


鼠标准星上下无规律变动。


对于没有鼠标准星特殊加密的游戏,我们通常在CE工具中搜索增加或者减少。


对于存在 鼠标准星特殊加密的游戏,我们通常在CE工具中搜索变动或者未变动。


另外,由于坐标等数据精度都是比较高的,所以我们通常搜索浮点数或者双浮点数。


(1)开始分析鼠标坐标内存地址


我分析的游戏是创世战车,这是一款FPS射击网游,由于我已经提前逆向过,所以我们的CE操作顺序依次是:


附加进程->切换为搜索浮点数->搜索未知的初始值 ->鼠标向上搜索增加 ->鼠标向下搜索减少


然后 鼠标向上搜索增加 ->鼠标向下搜索减少重复循环过滤,最后我们剩下9个内存地址,通过修改得知:0x23E3588  是我们的鼠标Y内存地址



此时,我们已经得到了鼠标Y的内存地址,这个时候,我们不必去搜索鼠标X的内存地址,只需观察该地址相邻或者附近的地址值的变化即可得知鼠标X。


因为鼠标XY坐标在游戏中存放是连续的,类似我们在上课写C语言结构体里面变量数据内存地址是连续的一样的道理。


那么如何查看相邻地址内存呢?CE有个自带的功能:



按照图示的标注的顺序,在下面的窗口编辑框内填入相关地址:



在这里解释一下为什么我们需要填入23E3500,因为鼠标Y地址是: 23E3588,鼠标X在附近的位置,所以我们存在一个取值范围,这个范围不是很大,所以我们填入了一个估值,填入后定义结构体,一切回车默认即可。


通过观察和修改,我们发现当修改23E3584这个地址时,鼠标的X准星会变动,由此我们得知了该游戏的鼠标坐标内存地址,即:


鼠标X:Crossout.exe+1963584

鼠标Y:Crossout.exe+1963588(该游戏基地址存放是以模块名+模块偏移存放的)



至此,我们的鼠标坐标内存地址分析完毕,当然了,分析这个还不够,下面我们来分析一下人物数组及其结构:


(2)开始分析人物数组


说到人物数组,我们必须要了解一下游戏中人物对象的存放形式,一般均为数组, 优点:


1、按照索引查询元素速度快;

2、能存储大量数据;

3、按照索引遍历数组方便。


而且这也是我们C/C++语言中常用的写法。


那么我们来分析一下该游戏,由于该游戏没有子弹数量,所以我们可以通过血量来分析该游戏的数据:


由于血量精度也比较高,所以存放形式也多为浮点数或者双浮点数,由于精度过高,所以我们不能够搜索精确数值,改为搜索两者之间的数值:



通过撞击建筑物或者其他车辆,使自身血量变动,然后过滤到血量地址:



这个时候,我们需要用到另外一款调试器:OllyDbg


我们附加进程,使用dd指令,查看血量地址,然后下硬件断点,寻找数组和基地址



程序断在了0x011299D9位置处,观察寄存器,我们得知eax为人物的临时对象地址,0x0C0为我们的血量地址偏移:0x39EE8FF0 + 0x0c0 = 0x39EE90B0 (eax)。



所以我们继续去追eax,通过单步call,我们发现eax实际上来源于上方的Call的返回值:




我们进入Call去追踪Eax来源,通过追踪我们发现了数组:



并且我们发现了数组的基地址:



关于最终数组的地址的寻址过程,在这里不再赘述,我只放出大概的OD逆向的注释,大家对照一下就可以了:







最终通过我们的分析得到数组的表达式:


dd   [[1C6E1F0]+(([[23E20D4]*7c0+2BE8+23CFD80]&0FFF)+2aad)*c]+0c0


其中,通过我们的分析,得知:0x23E20D4这个地址存放的使我们自身的数组的下标,所以,表达式可转换为


dd   [[1C6E1F0]+(( n*7c0 + 2BE8 + 23CFD80 ]&0FFF)+2aad)*c]+0c0   n为下标


分析完数组之后,我们接下来就来分析人物的结构了!


(3)开始分析人物结构


由于人物结构是一个结构体,该结构体的起始地址为人物对象地址,所以,我们继续用CE的结构体分析工具去分析人物对象地址,也就是刚才的eax地址:


通过观察,我们立刻就得到了人物名称的偏移量:0x68




通过观察和修改浮点数,我们观察到了人物坐标的偏移量:


人物左右X:0x2B0

人物前后Y:0x2B8

人物高度Z:0x2B4(个人习惯这个为Z)




由此,我们可以总结几个表达式了!!!


dd [[1C6E1F0]+(([n*7c0+2BE8+23CFD80]&0FFF)+2aad)*c]+0c0  人物血量


dd [[1C6E1F0]+(([n*7c0+2BE8+23CFD80]&0FFF)+2aad)*c]+068  人物名称


dd [[1C6E1F0]+(([n*7c0+2BE8+23CFD80]&0FFF)+2aad)*c]+02B0  人物X坐标


dd [[1C6E1F0]+(([n*7c0+2BE8+23CFD80]&0FFF)+2aad)*c]+02B8  人物Y坐标


dd [[1C6E1F0]+(([n*7c0+2BE8+23CFD80]&0FFF)+2aad)*c]+02B4  人物Z坐标


然后,我们就可以去游戏写个遍历器看一下了!走!去写遍历器!


(4)写遍历器查看游戏数据



大致逻辑如下,可能我的代码功底不是很好,让大家见笑啦~


因为该游戏房间人数最多为32人,所以我们for循环的次数为i

//定义遍历Address
 DWORD TempAddress, RetTemp, GetBase, ObjectAddress, ObjectValue;

 //基地址
 DWORD BaseAddress = GetProcessBaseAddress(ProcessId) + BasePtr;

 //数组基地址
 DWORD Address_Array = GetProcessBaseAddress(ProcessId) + ArrayPtr;

 char* Name = NULL;
 int Count = 1;



 for (int i = 0; i 32 ; i++)
 {
   //地址解密
   TempAddress = i * 0x7c0 + Address_Array + 0x2BE8;

   RetTemp = _ReadMemeryInt(_hGameHandle, TempAddress);

   //计算数组遍历地址
   RetTemp = ((RetTemp & 0x0fff) + 0x2AAD) * 0x0c;

   //基地址
   GetBase = _ReadMemeryInt(_hGameHandle, BaseAddress);

   //计算人物对象地址
   ObjectAddress = GetBase + RetTemp;


   //读人物对象地址
   ObjectValue = _ReadMemeryInt(_hGameHandle, ObjectAddress);

   //判断对象是否存在
   if (ObjectValue != NULL)
   {

     //读取人物血量
     float Bloat = _ReadMemeryFloat(_hGameHandle, ObjectValue + 0xc0);
     //读取人物名称
     Name = _ReadMemeryString(_hGameHandle, ObjectValue + 0x68);


     printf("第%d个人:   数组下标:%d   人物名称:%s     对象地址:%x   血量:%.3f ",Count, i,Name, ObjectValue, Bloat);

     ObjectAddress = NULL;
     ObjectValue = NULL;

     Count += 1;
   }
 }


游戏中的效果,我们遍历到了敌人的数据,比如重要的下标数据和对象地址:

 

(5)分析自瞄朝向


我们所有的数据基本上都分析完了,下面我们来分析一下网游自动瞄准的算法吧,在这里,我推荐大家用生活和游戏相结合的方式。


也就是游戏和生活联系在一起。


古代的时候,对于我们生活的地球,人们会讲“天圆地方”这么一个概念。


那么我们可以借鉴一下,把游戏中的地图看成方的,把我们看做坐标原点,然后建立一个直角坐标系,并且标注上北下南,左西右东:



然后我们先得知一个规律:

1.如果我们修正鼠标X和鼠标Y为0,那么游戏准星将指向一个东南西北的正方向。

2.前后移动如果人物X坐标未变动或者变动幅度小,则我们处在坐标系Y方向。

3. 前后移动如果人物Y坐标未变动或者变动幅度小,则我们处在坐标系X方向。


通过规律,然后通过观察,发现人物前后走动时,Y坐标变化剧烈,说明:

1.我们小车在Y轴方向上。

2.又因为向前减少,向后增加,说明我们的小车:坐北朝南,鼠标的位置此时指向了南方。


那么这个时候,我们把方向分析完了,我们来分析一下,鼠标坐标的变化规律:


我们此时是指向南方的,我们从南向北顺时针旋转鼠标,观察鼠标规律:


鼠标从南向北: 鼠标值的变化大致为:0--π



继续旋转:-π  此时π和-π的位置,也就是正北方,我们发现是重合的。


由此,根据游戏中的变化规律,我们可以作图:(鼠标的度数和象限和东西南北的关系)



这个时候,可能有的朋友会疑问了,画这个有什么用???


客官,且听我细细分说:

1.我们刚开始假想自己在坐标原点的位置;

2.我们通过1得到了不同象限内鼠标角度的范围。

那么,我们只需要知道敌人位于哪个象限就可以确定鼠标角度的范围,并且可以精确计算鼠标角度了。

所以,我们应该怎么确认敌人在哪个象限呢?


解:


既然游戏为一个直角坐标系,我们位于坐标原点,因此:

1.当敌人X>自身X  敌人Y>自身Y   敌人位于第一象限;

2. 当敌人X自身Y   敌人位于第二象限;

3. 当敌人X

4. 当敌人X>自身X  敌人Y


上面大家唯一要注意的就是正负的大小,不要搞混!


(6)分析自瞄的鼠标X坐标


因为我们得知了鼠标的变化规律,也得知了象限的变化,所以,我们只需要把我们和敌人的角度算出来就可以了!


那么应该怎么计算呢?


且听我细细分说!还是刚才的图:


我们以我们为起点,以敌人的坐标为终点,不考虑Z坐标,进行作图,连线,构造三角形!


那么根据几何知识,我们得知绿色的地方即

欢迎玩家到【wan玩得好手游】查看最新变态版手游攻略,只需要在百度输入【wan玩得好手游】就可以浏览最新上线送满vip的变态手游攻略了,更多有关BT手游的攻略和资讯,敬请关注玩得好手游!

更多...

热门推荐

更多...

相关文章