0


浅谈非内存对抗类和AI自瞄类FPS作弊程序原理及常用反反作弊措施与反作弊应对手段(中)

往期文章:

浅谈非内存对抗类和AI自瞄类FPS作弊程序原理及常用反反作弊措施与反作弊应对手段(上)

3. 基于虚拟化技术的KVM-内存外挂

    Kernel-based Virtual Machine的简称,是一个开源的系统虚拟化模块,自Linux 2.6.20之后集成在Linux的各个主要发行版本中。它使用Linux自身的调度器进行管理,所以相对于Xen,其核心源码很少。KVM已成为学术界的主流VMM之一。

KVM的虚拟化需要硬件支持(如Intel VT技术或者AMD V技术)。是基于硬件的完全虚拟化。而Xen早期则是基于软件模拟的Para-Virtualization,新版本则是基于硬件支持的完全虚拟化。但Xen本身有自己的进程调度器,存储管理模块等,所以代码较为庞大。广为流传的商业系统虚拟化软件VMware ESX系列是基于软件模拟的Full-Virtualization。

             在游戏作弊领域,由于各种作弊功能的实现需要依靠获取游戏的内存数据,获取数据的方法大多是外挂作者编写或者购买专门用于绕过反作弊的内存读写驱动,从操作系统的内核态读取数据。但是这样的驱动程序往往受到了反作弊团队的高度重视,反作弊程序从某种方面来说可以是一个专门用于驱动对抗的程序,所以大部分情况下一个编写好的驱动往往才使用了很小一段时间就会被反作弊程序定位,进而封禁。驱动对抗领域反反作弊的成本居高不下,出于减小对抗成本,简化外挂开发流程,追求更加稳定的外挂使用周期,外挂作者将目光放在了KVM虚拟机技术。

            简单来说,KVM就是将游戏程序放在一个干净的、专门提供给游戏运行的独立的虚拟机当中。专门用来运行游戏的虚拟机系统经过深度优化定制,完全移除了任何可能被游戏反作弊系统检测到并标记为虚拟机的特征,它与正常的操作系统无疑,并且高度简化的操作系统,使得游戏调用计算机资源更加高效,往往游戏的画面表现、游戏帧率都有极大优化。

            当游戏运行在虚拟机上的时候,游戏会正常地将游戏过程中需要的各项数据保存到内存当中,而外挂作者通过读取虚拟机的内存数据加上特定的偏移量,就可以间接地获取到游戏的内存数据。而这种读取的行为在游戏反作弊视角看来是完全“无痕”的,因为外挂是直接读取的虚拟机程序的内存数据,并没有直接读取游戏的数据,在反作弊看来,这只是操作系统正常的调用行为。虚拟机中运行游戏,主机上运行外挂,并且将诸如透视、物品信息等信息绘制在主机的屏幕上,再将虚拟机的游戏画面全屏,从视觉效果上与传统内存外挂的界面别无二致。

            KVM技术,相当于将游戏及其反作弊放在了沙箱中运行,与本机的操作系统环境完全隔离,反作弊的各种检测手段在沙箱中便形同虚设,只能通过诸如行为检测等被动检测方法来检测异常行为,但往往外挂程序以及在这一方面做的滴水不漏,高度拟真的鼠标移动轨迹、非直接的敌方目标显示(比如CSGO的声纳外挂)再加上作弊者主观的高超“演技”,使得反作弊的行为检测变得不那么有效。

            从代码层面来说,传统的外挂作者只需要想办法定位到虚拟机中游戏内存地址的偏移量,其余的写法直接参考内存外挂的正常写法即可实现KVM内存外挂。

            但是KVM技术现如今不仅仅局限于内存外挂作弊,事实证明传统的找色外挂、新兴的AI外挂也可以结合KVM虚拟机技术达到规避反作弊检测的目的。

4. 基于物理外设硬件的DMA外挂

            原理部分直接po了百度百科的内容过来。
           直接内存访问(DMA,Direct Memory Access)是一些计算机总线架构提供的功能,它能使数据从附加设备(如磁盘驱动器)直接发送到计算机主板的内存上。

            

外设与存储器之间以及存储器与存储器之间的数据传输,通常采用程序中断方式、程序查询方式和DMA控制方式。程序中断方式和程序查询方式都需要CPU发出输入/输出(In/Out,I/O)的指令,然后等待I/O设备完成操作之后返回,期间CPU需要等待I/O设备完成操作。DMA在传输存储器和I/O设备的数据时,无须CPU来控制数据的传输,直接通过DMA控制器(direct memory access controller,DMAC)完成外设与存储器之间以及存储器与存储器之间的数据高速传输。 [3]

DMA传输原理

一个完整的DMA传输包括DMA请求、DMA响应、DMA传输和DMA结束4个步骤。DMA传输原理如图1所示,图中I/O设备为源端设备,由I/O设备向目的端设备(存储器)传输数据,其DMA的基本传输过程如下:①CPU对总线控制器进行初始化,制定工作内存空间,读取DMAC中的寄存器信息,了解DMAC的传输状态[1];②I/O设备向DMAC发送DMA请求(DMA request,DREQ),DMAC收到此信号后,向CPU发出总线保持信号(HOLD); ③CPU当前总线周期执行结束后发出总线响应信号保持确认(hold acknowledgment,HLDA); ④DMAC收到总线授权后,向I/O设备发送DMA响应信号DMA确认(DMA acknowledgment,DACK),表示允许I/O设备进行DMA传送;⑤开始传输时,DMAC首先从源地址读取数据并存入内部缓存中,再写入目的地址,完成总线数据从源地址到目的地址的传输[1];⑥DMA传输完成后,DMAC向CPU发出结束信号,释放总线,使CPU重新获得总线控制权。一次DMA传输只需要执行一个DMA周期,相当于一个总线读/写周期,因而能够满足外设数据高速传输的需要。 [3]

DMA是所有现代电脑的重要特色,它允许不同速度的硬件设备来沟通,而不需要依于中央处理器的大量中断负载。否则,中央处理器需要从来源把每一片段的数据复制到寄存器,然后把它们再次写回到新的地方。在这个时间中,中央处理器对于其他的工作来说就无法使用。

DMA传输常使用在将一个内存区从一个设备复制到另外一个。当中央处理器初始化这个传输动作,传输动作本身是由DMA控制器来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存去。像是这样的操作并没有让处理器工作拖延,使其可以被重新调度去处理其他的工作。DMA传输对于高性能嵌入式系统算法和网络是很重要的。 举个例子,个人电脑的ISADMA控制器拥有8个DMA通道,其中的7个通道是可以让计算机的中央处理器所利用。每一个DMA通道有一个16位地址寄存器和一个16位计数寄存器。要初始化数据传输时,设备驱动程序一起设置DMA通道的地址和计数寄存器,以及数据传输的方向,读取或写入。然后指示DMA硬件开始这个传输动作。当传输结束的时候,设备就会以中断的方式通知中央处理器。

"分散-收集"(Scatter-gather)DMA允许在一次单一的DMA处理中传输数据到多个内存区域。相当于把多个简单的DMA要求串在一起。同样,这样做的目的是要减轻中央处理器的多次输出输入中断和数据复制任务。 DRQ意为DMA要求;DACK意为DMA确认。这些符号一般在有DMA功能的电脑系统硬件概要上可以看到。它们表示了介于中央处理器和DMA控制器之间的电子信号传输线路。

            为了提高DMA设备的数据拷贝效率,针对DMA原理设计出来了PCIE接口的外置DMA设备,通过专用的芯片及独立的PCIE通道,加上诸如Type-C高速USB接口,使得数据拷贝速度再创新高。DMA设备的设计本意就是为了绕过CPU直接去访问内存数据,用于工业及其余领域中数据采集或者数据同步的作用。

            由于FPS领域的游戏外挂,其核心就是对于游戏内存数据的读写,外挂稳定性也与读写行为是否会被反作弊系统检测挂钩,既然DMA可以直接绕过CPU,就可以直接物理绕过操作系统驱动层面的反作弊检测,基于内核编写的检测也失去作用。

            DMA作弊往往是与双机技术相结合。DMA在获取到了主机上的游戏内存数据后,将数据同步传输到第二天电脑也就是副机上,副机上运行的外挂程序可以对这些数据进行分析,再将画面绘制输出到副机上,通过视频融合器:一种可以将外挂绘制画面与输入画面混合后输出的专门设备,将画面与主机的游戏画面融合,输出到显示器上。或者通过Kmbox等第三方键鼠设备,模拟鼠标移动控制主机达到自动瞄准等功能。

             对于主机来说,既没有直接的内存数据读写,又没有可疑的重叠窗口绘制(内存外挂往往会把诸如人物坐标的框框和物品等信息绘制在一个透明的窗口上,再将窗口叠放在游戏的窗口之上,针对这一绘制行为反作弊有针对性检测),所以早期对于DMA的作弊,反作弊都不能起到有效的检测。

            而且从外挂作者的视角来看,拥有了DMA设备之后,就不需要再将精力放在数据读取之上,因为传统的内存外挂作者往往需要费尽心思去寻找反作弊程序的检测代码,利用驱动和汇编知识将检测代码处理,比如直接用汇编语言将部分检测代码直接NOP掉。DMA设备往往会提供封装好的DLL供程序员调用,外挂作者只需要获取游戏的进程ID,再加上特定数据的内存地址和偏移量就可以轻而易举的获取到关键数据来开发外挂功能。

            以Apex英雄举例:

            
int main(){
    const char* cl_proc = "cleaner.exe";
    const char* ap_proc = "R5Apex.exe";
    //const char* ap_proc = "EasyAntiCheat_launcher.exe";
    PrintVarsToConsole();

    //Client "add" offset
    uint64_t add_off = 0x5650;

    std::thread aimbot_thr;
    std::thread actions_thr;
    std::thread itemglow_thr;
    std::thread vars_thr;
    std::thread recoil_thr;
    std::thread debug_thr;
    
    while(active)
    {
        if(apex_mem.get_proc_status() != process_status::FOUND_READY)
        {
            if(aim_t)
            {
                aim_t = false;
                actions_t = false;
                item_t = false;
                recoil_t = false;
                g_Base = 0;

                aimbot_thr.~thread();
                actions_thr.~thread();
                //itemglow_thr.~thread();
                //recoil_thr.~thread();
                debug_thr.~thread();
                
            }

            std::this_thread::sleep_for(std::chrono::seconds(1));
            printf("Searching for apex process...\n");

            apex_mem.open_proc(ap_proc);

            if(apex_mem.get_proc_status() == process_status::FOUND_READY)
            {
                g_Base = apex_mem.get_proc_baseaddr();
                printf("\nApex process found\n");
                printf("Base: %lx\n", g_Base);

                aimbot_thr = std::thread(AimbotLoop);
                actions_thr = std::thread(DoActions);
                //itemglow_thr = std::thread(item_glow_t);
                //recoil_thr = std::thread(RecoilLoop);

                if (DEBUG_PRINT)
                {
                    debug_thr = std::thread(DebugLoop);
                    debug_thr.detach();
                }

                aimbot_thr.detach();
                actions_thr.detach();
                //itemglow_thr.detach();
                //recoil_thr.detach();
            }
        }
        else
        {
            apex_mem.check_proc();
        }

        std::this_thread::sleep_for(std::chrono::milliseconds(12));
    }

    return 0;
            代码中的apex_mem类就是基于封装好的DMA-DLL编写的内存读写类,而外挂代码中不再需要作者针对反作弊而去做出特别的处理,专注于功能的开发即可。
            可笑的是,随着DMA技术的落地,再加上国外外挂作者积极地开源外挂源码,使得国内有越来越多的人冒着触犯刑法的风险,通过各种渠道获取到游戏最新版本的偏移量替代源码中过时的数据后,编译外挂进行贩售。并且DMA外挂的价格相较于传统内存外挂更加昂贵,一个月300、500的定价竟然是“性价比拉满”的选择。

            起初DMA仅仅活跃于国外的逃离塔克夫、PUBG、CSGO游戏作弊圈子,后来国外的外挂作者将相关的外挂源代码开源在了Github上,并将DMA板子的原理图、固件源码一并开源。由Github和UnKnownCheats平台传入国内,国内外挂作者基于开源的源码二次开发将其应用到国服FPS游戏诸如穿越火线、逆战、CFHD、无畏契约等。外挂的种类也不仅局限于传统的透视自瞄,引申出来雷达、物品上色、无后座等花样繁多的功能,因为FPS类游戏关键数据都是本地计算的特性,获取了内存数据就可以基于数据进行无限的创作。

            DMA硬件的固件烧录、配合DMA的外挂程序卡密售卖,加上各种第三方的键鼠盒子、外设,一条完整的双机、DMA外挂作弊黑产链条形成。在DMA作弊问世不久的年份,正常玩家可以说是饱受其害。

            近年来随着诸如国内的ACE反作弊团队对于DMA外挂这一新型作弊方式的高度重视,DMA外挂在一定程度上予以了打击,但是早已铺开的庞大的黑产市场警醒着人们,这场新型反作弊的没有硝烟的战争只是开始,隐藏在地表深处的毒瘤还很庞大,外挂攻防之路还十分坎坷。

5. 基于Yolo目标检测框架的AI自瞄外挂

             基于Yolo目标检测框架应用在FPS游戏上实现AI自瞄的相关视频在bilibili上最早可以追溯到2019年(实际上2016年Yolo问世后就有相关的帖子讨论将其应用在游戏作弊领域,但是最早都是将Yolo框架与搬砖类游戏结合比如梦幻西游、DNF之类的,利用目标检测完成自动化寻路、挂机脚本以及打金等功能),但是当时并没有太多人关注,Yolo框架刚问世不久,无论是效率、速度上都有欠缺,所以在FPS领域当时的效果仅仅是做到了类似于主机端手柄那样的辅助瞄准效果,并没有到达影响平衡性的地步。更多的是验证Yolo框架应用FPS领域自瞄等作弊功能的可行性。那时候国内流行的FPS游戏作弊还仅仅是停留在以驱动内存为内核的内存外挂作弊层面,DMA在那个时候也并没有宣传推广出来,游戏厂商的对抗仅仅是与内存外挂对抗。

            后来随着Yolov4-tiny、Yolov5、v7、v8等版本框架的推出,结合CUDA加速、TensorRT量化加速、Direct_ML加速等技术的加持,高效、快捷、准确度得以保证,配合专门针对FPS游戏制作的模型,AI自瞄这一新型外挂在21年之后得到疯狂传播,以cvcheat为代表的AI外挂制作团队借此疯狂敛财,并在23年9月落网。但是cvcheat的落网并没有抑制国内AI自瞄作弊的发展势头,随着更加便捷的易语言Yolo模块的封装,近年以易语言为主要编程语言开发的AI自瞄外挂遍布国内外挂市场。

            相较于内存外挂需要较高的编程门槛,基于Yolo目标检测框架的AI自瞄的代码实现更加容易,并不需要过高的门槛,再加上互联网技术平台上唾手可得的教程,使得人人都可以制作,可与当你的找色类外挂相提并论。

            AI自瞄外挂大体分为8步:

            (由于网上各种教程都很详细,这里就不再列出详细代码,仅仅从原理角度分析过程)

            1. 实现循环截取电脑桌面局部图像,由于实现自瞄只需要以游戏准星为中心向外的正方形区域图像即可,不需要全屏截取以节省电脑资源开销,预留足够资源给游戏及Yolo推理。一般截取大小在320x320或者最大640x640范围的图像即可(320和640是由Yolo模型训练时候默认的推理大小决定的,大部分开源二改作者并不是精通Yolo目标检测框架,更多的只是应用层面的“程序员”,即便Yolo框架推理时候可以输入不同大小的图片,但是大多数作者并不会在此处理图像,所以大部分开源源码都是以输入320或者640尺寸图像为主)。常用到的截图第三方库有Opencv、Mss、DXGI、D3dshot,以及cvcheat团队制作的版本当中用到的注入Obs Studio,从显卡图像输出层Hook直接获取图像的方法获取截图图像,只要截图效率足够快,满足一秒采集60张图片,即稳定截图速度达到60帧以上就可以实现内存级别的AI锁死自瞄效果。相关代码可以参考以下帖子:

Python使用MSS截屏_python mss截图-CSDN博客

python调用dxgi实时快速截屏 - CSDN文库

C++ Windows下使用DXGI实现屏幕截图_dxgi截屏指定范围-CSDN博客

截图的方式有很多种,用作AI自瞄的常用截图方式有以上几种。

        2. 当获取到了截取的桌面图像后,就要对图片进行预处理。常做的就是将图片转化为numpy多维数组的数据结构,将图片四通道色域转化为三通道RGB格式。在python语言中,如果当前设备的Cuda加速可用,一般会使用nupy,即基于cuda加速的numpy库以加速图片处理的速度。将处理后的图片传入Yolo推理框架进行推理。截图常用多线程进行推理。截图一个线程、推理一个线程、监听鼠标键盘一个线程、移动一个线程。多线程不仅提高了截图、推理的效率,也可以将硬件资源利用最大化。

        3. Yolo框架推理阶段。现阶段国内AI自瞄常用的Yolo推理框架有Yolov4-tiny,Yolov5-6.1\6.2版本,Yolo-X,Yolov8及Yolov9。其中最为流行的是Yolov5-基于CUDA加速以及TensorRT量化加速,针对NVIDIA显卡。对于AMD处理器及显卡常用Direct-ML加速,虽然效率远不及前两者,但是给了国内AMD显卡用户一个选择,虽然大部分用户还是NVIDIA显卡。确定使用的推理框架后,前往Github搜索相关关键字,有相应框架作者的部署源码,将源码拷贝,根据作者给出来的环境部署教程在本地部署CUDA加速工具包以及TensorRT环境,拷贝detect源码,将前文获取到的截图数据传入detect参数后即可得到预测框的坐标,拿到了坐标之后就可以进行下一步数据处理。

        4. 得到坐标之后,根据截取图片的大小可以反推出预测框坐标基于当前分辨率下桌面的精确坐标,这个坐标便是屏幕上识别出来的“敌人”的坐标。国内常用坐标计算方案是通过游戏FOV视角进行三维转二维坐标平面变换,因为得到的推理坐标是基于游戏内FOV缩放后的坐标,经过数学转换后便可以得到游戏内的具体坐标,即需要鼠标相对于当前准星需要移动的距离,也就是玩家需要操控准星从发现敌人到移动到敌人身上的操作。参考博客(只是原理示意,具体坐标公式我也没存):

视角与镜头焦距换算_视场角为160°左右的镜头焦距长度多少-CSDN博客

        5. 当获取到坐标之后,便是部位的处理。自瞄外挂可以根据需要选择瞄准头部、胸部等部位,这个坐标换算一般很简单。返回的预测框坐标里面包含了预测框的高度,大约高度x 0.22~0.25,也就是从预测框顶部向下大约三分之一的部分就是头部到脖子的位置;高度x 0.4~0.5大约是身子的位置,更多位置以此类推,按照比例计算。

        6. 经过一系列计算之后得到了需要移动的相对坐标,接下来便是调用鼠标移动部分。以国内游戏举例,如穿越火线,CFHD,生死狙击2等游戏,直接调用Win32系统Api中的Sentinput函数,通过系统预留的接口便可以模拟鼠标移动,在上面这些游戏里面都可以正常移动并且不会触发检测(貌似压根没有鼠标输入检测)。像是国服无畏契约,逆战这些游戏,利用Sentinput系统Api移动就不行了,无畏契约首先就屏蔽了这一虚拟鼠标模拟方式,逆战则是会检测模拟信号输入,触发反作弊。所以就需要用到了前文提到的Kmbox等一类的键鼠盒子。这种盒子的特点就是外置硬件设备并且可编程,也就是说程序员可以通过简单调用他们提供的dll,实现控制这些连接在电脑上的真实存在的键鼠硬件发送信号控制鼠标移动,因为这种鼠标信号的输入与咱们正常使用鼠标时候的输入是一模一样的,所以游戏反作弊并不会屏蔽,达到了自瞄的目的。

       类似的键鼠盒子有:易键鼠、飞翼来、北京文盒、无涯键鼠盒子、Kmbox系列、Knight系列、幽灵键鼠、叛逆硬件。这些键鼠盒子均可在如淘宝的网购平台购买到。

       7. 轨迹拟真。得到的坐标并不能直接用作自瞄,因为生硬且快速的自瞄会直接触发反作弊针对玩家行为的检测,所以AI自瞄作者需要做到尽可能将移动的坐标“柔化”,让自瞄的轨迹不那么生硬,更加接近真人移动鼠标的轨迹,在保证了自瞄的准确性、速度的同时,降低反作弊的行为检测。常用的方法是将绝对移动改为相对移动,将移动的重点坐标进行二阶、三阶贝塞尔曲线拟真,PID控制算法拟真,非线性ARDC控制算法拟真后,将一段自瞄坐标分解为若干细小移动坐标分次移动(因为鼠标的回报率通常在1000HZ,也就是一秒可以检测鼠标移动1000次,所以这其中留给拟真轨迹的冗余量其实有很多,大可以把一段自瞄坐标分成100或者500次去移动,密集的点就可以形似看成曲线,也就更加接近真人的移动轨迹)来规避反作弊的检测。

** 截止截稿,又有一种新型模拟鼠标移动的方式便是基于操作系统内核态层面,也就是R0层的驱动IO模拟,给操作系统安装一个虚拟的人体学输入设备,通过从内核态模拟IO设备输入并将信号转接到当前连接电脑的设备上,也就是给正常鼠标的输入信号中插入一段模拟出来的信号达到额外的鼠标移动方式来实现。这个方法以及可以突破瓦洛兰特以及无畏契约基于屏蔽异常鼠标输入方式的反作弊措施,达到无需外置硬件即可实现单机AI**自瞄的效果。

        8. 以上几个部分组合在一起就可以基本实现AI自瞄了,但是针对日益强劲的反作弊,AI自瞄外挂作者通常会对AI自瞄版本进行进一步深度包装以进一步规避反作弊的检测。事实证明在21年AI自瞄刚问世的时候,反作弊并没有针对AI自瞄有针对性检测,即便最基本的AI自瞄都可以规避反作弊,因为这一新型作弊方式没有对游戏数据进行读取写入,不会触发传统反作弊检测规则。随着AI自瞄逐渐走进大众视野,反作弊对于AI新型作弊有了针对性检测,作者们也想出来了很多技巧去进行反作弊攻防。**下一大节会重点分析。**

本文转载自: https://blog.csdn.net/qq_50803262/article/details/136686001
版权归原作者 LeonXrek 所有, 如有侵权,请联系我们删除。

“浅谈非内存对抗类和AI自瞄类FPS作弊程序原理及常用反反作弊措施与反作弊应对手段(中)”的评论:

还没有评论