浅谈FPS子弹追踪实现以及防护
2020-04-29 13:14:18 Author: bbs.pediy.com(查看原文) 阅读量:604 收藏

        开场白和表情包我就不加了了,文采和资源没这么丰富,直接步入正题。本次聊聊的功能为目前fps较为热门功能:子弹追踪。

        该功能呢早期主要是火在pubg系列的游戏,因为在类似pubg系列游戏中,自瞄显得稍微鸡助,然后某些大佬就弄出了这么一个功能,子弹追踪。其实它的一个效果与自瞄不同,自瞄的表现效果为准星死死锁住敌人。可子弹追踪的表现效果为子弹死死锁住敌人,也就是说准星在不需要锁住人的情况下开枪也能对敌人造成伤害,下面放一个图直观的感受一下。

                                                                   GIF链接:gif

        该gif为手机录制,所以画质很渣,但是不影响看效果。可以明显看到他虽然没有瞄准敌人,但是敌人却被打出了健康的绿色血液,这就是子弹追踪的效果。

       效果我们看到了,那么该功能的一个实现原理是什么呢?顾名思义,子弹追踪就是子弹追着人打嘛,只要对子弹下手就能实现了,看似如此可真是如此吗?那我们换一个思维模式,我们当前要实现一个功能是不是准星在无需瞄准人的前提下开枪也能对敌人造成伤害?那么只要我们实现了这个功能,那我们的这个功能是不是也能称之为子弹追踪?这两句话很关键,大家细品。只要弄清这两个问题后就不会再被‘’子弹‘’两个字给骗到了。另外,如果大家常年混在看雪里褥羊毛的话就会发现,其实早期就有人发布过一种子弹追踪的实现方式,那就是飞郁培训的大佬讲师任鸟飞。这里就直接上帖子链接,有兴趣的大家可以看看:https://bbs.pediy.com/thread-251701.htm

除了修改击打区域达到子弹追踪,还有什么方法能达到吗?俗话说“条条道路通罗马”,那么该功能实现的方法肯定不止一种,就看你脑洞能不能想到。下面呢我讲举一种实现方法来讲解。

        我不知道大家有没有仔细思考过一个根源问题,那就是为什么FPS存在准星这个东西?答案很简单:用来瞄准目标。所以我们能准星指哪打哪。可是问题来了,请问游戏是怎么知道我们准星瞄准的是哪里?打的是哪里?请注意,这里我说是两个问题。我相信大部分人都没有真正去思考过这个问题,因为他们基本上都把这两个问题归结为一个问题。其实在我们不断深层的挖掘这个问题的时候,答案已经显得容见。那就是游戏会不会把我们从瞄准到射击敌人的这个过程分为两个部分,一个是准星的变动(准星的变动所带来的的影响为视角的变动,下面我都以视角来描述),另一个是实际射击。为了确认这两个想法是否正确,我们用游戏实践一下。第一步得找到视角的坐标,也就是鼠标XY。

                                      

不难发现随着鼠标XY变化,视角也在变化,故第一个想法成立。我们来看看第二个,既然用于实际射击,那么在我们开枪的时候鼠标XY必定作为参数传进来,此时我们只需要找到开枪call下断,然后开一枪后看一下堆栈是否存在鼠标XY即可。

                          

断点断下后往下一翻,果然有鼠标XY,那么就说明从瞄准到射击的确分为两个部分。当我们确认这两个想法之后,好玩的事来了。我们回忆一下,我们是不是要实现一个准星在无需瞄准人的前提下开枪也能对敌人造成伤害的功能,那么我们是不是可以做一下手脚?当我们开枪的时候我们不用游戏本身所提供的视角坐标,而是用我们提供的坐标,这样就能在不影响原视角的情况下让子弹往我们提供的坐标射击,于是文章开头的那个效果图就出来了。至此,子弹追踪就已经实现。不过这种子弹追踪的实现方式在江湖中有它自己的名字-----视角追踪或静默自瞄。这里说一下,之所以也称之为静默自瞄,只因为该追踪本质上还是属于自瞄,只不过是我们原视角在不产生变动的情况下进行了自瞄。

        分析也分析完了,那么怎么去实现呢?两种方式:

第一种、需要大量的逆向功底,就是分析开枪call在什么时候被赋值了实际射击坐标,然后hook即可实现。

第二种、有句古话“擒贼先擒王”,既然开枪的时候需要去读取视角坐标,那么我们就直接在访问视角坐标的代码段进行处理岂不美哉。

Tip: 第二种方法虽然不如第一种方法要求的技术含量高,但是根据本人这段时间的测试,发现很多游戏都能实现,并且危害性大。故讲解该种方法的实现,也希望游戏产商早日和谐该功能。

        我们来访问一下视角坐标

                                                                           

发现有三条,而且无论我们改变视角还是开枪,都不会出现新的访问,那么我们只能从这三条处理。我们抛开第三条不看,因为第三条是属于给视角坐标赋值语句,我们要看的只是访问语句。这样就只剩下两条了,我们先点击第一条看看。

我们再来看第二条语句的

         

       这两段代码几乎相同,都是把视角坐标取出来后赋值给另一个地址。经过我们上面分析,瞄准和射击分为两个部分,他们都是需要去访问读取视角坐标的,巧的是这里对视角坐标访问恰好就是有两个,那么我们可以怀疑一下这两个语句分别就是对应瞄准和射击。我们直接nop看效果,先nop第一个

                                                                  

        因为eax和eax+4分别存储视角Y和X,所以得nop两条语句。接下来我们进入游戏看看

                                     

        我们发现nop之后虽然我们没法改变视角,但是我们会发现,鼠标XY竟然在改变,然后我们开枪,发现子弹依旧是打在墙上,这就尴尬了。。。。。我们添加一个机器人,我们走到他的面前,我们把准星对准他的头部,然后重新nop该处代码。

                                     

神奇的一幕来,无论我们朝他头部开多少枪,就是打不了。为什么?我们还原代码

                                       

        发现我们准星此时指的是这个位置,此时我们把视角瞄准敌人后再次nop

                                     

        就变成了这样,我们用手枪打一下。

                               

发现敌人被我们爆头了。我们就能百分百确认了,该代码段为控制视角,真实控制射击的是第二条访问语句或者直接是鼠标XY。现在呢,已经可以写代码了,不过这里我只提供关键代码,其余代码大家可以自己完善。

    在研究的时候我们发现一旦nop之后,视角直接发生改变,而且直接把人物指向0的位置,是因为我们nop后视角坐标得不到赋值,就一直为0。那我们我们想让我们视角保持不变怎么办?那就得需要一个变量来记录。当我们开枪的时候,先把当前的视角坐标记录,然后把这个记录的值写入视角坐标,这样就达到一个锁视角的效果,然后再通过自瞄算法把自瞄角度算出来再写入鼠标XY中,最后实现追踪效果,追踪完毕后再恢复代码。那么如何确定视角坐标地址呢?

        首先我们已经找到控制视角的代码段了,不难发现,控制视角的关键语句为的两条

client.dll+CB0D0 - 8B 44 24 04           - mov eax,[esp+04]
client.dll+CB0D4 - 8B 10               - mov edx,[eax]
client.dll+CB0D6 - 89 91 040F0000            - mov [ecx+00000F04],edx           --------->视角Y
client.dll+CB0DC - 8B 50 04             - mov edx,[eax+04] 
client.dll+CB0DF - 89 91 080F0000            - mov [ecx+00000F08],edx           --------->视角X
client.dll+CB0E5 - 8B 40 08             - mov eax,[eax+08]
client.dll+CB0E8 - 89 81 0C0F0000            - mov [ecx+00000F0C],eax
client.dll+CB0EE - C2 0400              - ret 0004ret 0004

        那么我们可以直接采用hook技术,把记录的值写入这两地址里即可。以下为部分代码

    //静默自瞄
        if (g_bBulletTrack)
        {
                if (GetAsyncKeyState(VK_LBUTTON) != 0 && dwTargetObj != 0)
                {
                    if (Data::getHp(dwTargetObj) > 0)
                    {
                        bAimLock = true;
                        AimAngle = Data::getAimAngle(Data::getBonePos(LocalPlayer.obj, Bone_Head), Data::getBonePos(dwTargetObj, Bone_Head));
                        AimPunch = Data::getAimPunch(LocalPlayer.obj);
                        AimAngle.x -= AimPunch.x;
                        AimAngle.y -= AimPunch.y;
                        BulletTrack::Track(true, AimAngle);
                    }
                }
                else
                {
                    BulletTrack::Track(false, AimAngle);
                    bAimLock = false;
                    fValue1 = 0;
                }
         }
        
        
    /*追踪实现*/
    void Track(bool state,Vector2 angle)
    {
        if (state == true)
        {
            g_dwTrackSwitch = 1; //开
            g_AimAngle = angle;
            lockScreenView(); //锁定视角
            WriteMem<FLOAT>(ReadMem<DWORD>(g_dwEngineModule + m_Mouse) + m_offsetMouseY , g_saveMouse.y);  //写自瞄角度
            WriteMem<FLOAT>(ReadMem<DWORD>(g_dwEngineModule + m_Mouse) + m_offsetMouseY+4, g_saveMouse.x);
        }
        else
        {
            if (g_dwTrackSwitch == 1)
            {
                g_dwTrackSwitch = 0; //关
                resumeScreenView(); //恢复视角
            }
        }
    }
  • 最总效果点击这个看吧,我已经忘记如何上传gif了。。。。

        正如我在文中多次提到,该种追踪的实现方法在很多款游戏我已经实现了,页游到端游的部分游戏都会存在,并且没有一丝丝的检测。游戏厂商应该对此重视一下,稍微对其关键部位进行检测,并对鼠标XY的数据进行校验,以防不法分子对其进行篡改。

        本文提到的 准星、视角、鼠标 均为一个东西。

        既然大家都这么热情,我就简单说说把。对于提到的这个追踪只能给自己看,敌人视角还是能看到锁住的这个问题我确实没去注意到,这里算是我的一个失误。但是抛开这些小问题,你们都觉得这个不是子弹追踪。那行,就再聊聊。

        子弹追踪目前市场上热门的分三种,魔术子弹、弹道追踪、视角追踪。大致是这三种,其他的肯定还是有,这里我就不阐述。不过这三种的区别我简单讲一下。

        魔术子弹:直接在子弹产生的那个时候把子弹坐标改成敌人坐标,直接把敌人击杀。pubg的穿山爆车,隔着各种障碍物秒人就是这个,很多人以为是子弹穿墙,其实不是。

        弹道追踪:这个虽然是和魔术子弹都是从子弹下手,但是他不同于魔术子弹,这个他不能无视障碍物,效果就是和视角追踪一样,只不过他这个是对子弹做了处理。

        视角追踪:就是我文章提到的。我就不说了,你们如果混黑产就去看看某平,某战场的源代码,看看是不是这个东西。

        其实我文章开头已经提到两个内容了,一个是我只讲一种的实现原理,另一个就是不希望大家被子弹追踪这个名字给约束。功能是叫这个名字,但是实现是另外一回事,你能实现这个功能的效果,那总的来说也能称之为子弹追踪,只不过可能不太准确。就好比你实现透视方法很多种,雷达,方框,Z轴等等,更牛逼还是直接画在h5,可最终的目的还是看到敌人玩家。功能的名字是固定的,但是思维碰撞是不定的,你研究一样东西你不能总在抠字眼,老人都常说,不管黑猫白猫,能抓到老鼠都是好猫。如果非要否定,那也没办法。我写出来是为了技术分享,别无他意。

[培训]科锐逆向工程师培训班38期--远程教学预课班将于 2020年5月28日 正式开班!

最后于 11小时前 被PlaneJun编辑 ,原因:


文章来源: https://bbs.pediy.com/thread-259175.htm
如有侵权请联系:admin#unsafe.sh