万字长文带你深入了解“游戏外挂”?

万字长文带你深入了解“游戏外挂”?

前言首先在此声明一下,文章只用于交流学习

image

 

(就想打个鸟游戏怎么还天天遇见挂狗,我真靠了)

本文讲了各种外挂的实现原理(如内核 直装等)

本文分为三部分:

  • 前言

  • 原理

  • 实现


前言:

为什么有的人说游戏外挂开发门槛极低,但为什么又有的人说游戏外挂开发门槛极高?

只有了解了外挂原理,我们才能对其制衡。

其实手游外挂圈就像修仙一样,是有技术等级和小圈子之分,大致总结如下:

  • 会使用GG修改器、Cheat Engine修改器等内存工具对游戏内存空间进行修改

  • 会使用易语言、GG修改器、XScript等工具编写简单修改内存脚本或程序

  • 会使用GG修改器、Cheat Engine等工具扫描出指针链并编写相关简单脚本或程序

  • 会使用AndroLua,AIDE,C4Droid等工具编写出简单的安卓应用程序

  • 了解外挂基本原理,会使用Android Studio,VS Code等工具开发出自己理想中的外挂程序

  • 会使用ida等反汇编工具分析游戏逻辑代码,Hook、内存读写等技术改变游戏运行逻辑等

  • 自己能研发出外挂独家技术,并且对于安卓系统有一定了解

当然对于高手这来说,以上均是入门皮毛,真正难的技术在于反反作弊,这也是为何即说外挂入门简单,又说外挂开发门槛高的原因,对于大部分外挂开发者来说,开发外挂都是为了赚钱。


原理/分类:

其实核心点在于内存,在内存中是正在运行的指令以及缓存等数据,功能性外挂通常通过修改内存数据,改变其运行原理,达到其想要的效果,例如通常在游戏中会有个全局变量来记录当前移动速度,可以使用Cheat Engine、GG修改器等内存工具找到并改变这个值就可以实现加速的效果。外挂做的一切操作,例如注入,hook,反游戏检测等都是为了最终读取/修改内存数据,而我们反作弊系统,其一思路就是想办法让其无法读取/修改内存。

其实常见外挂有

内存型:也就是通过读写内存来实现功能

封包劫持:通过抓取游戏对局数据包进行读取/修改/重发开实现想要的功能

AI协助:通过FPS类游戏人物模型训练AI模型,匹配敌人在屏幕中的坐标并将准星瞄准/预判到人物坐标位置开火击杀。

以上类型仅内存型最为猖獗,而其他实现难度大(反驳这句话的人基本只会玩个GG),AI型由于手机算力太低,通常会使用电脑来代为计算。

说到这里也讲一下我目前已知的AI类外挂的方案,不过这类外挂并未出现在市场中,因为无法大范围使用,且非常麻烦。

手机上会实时录屏同步到电脑屏幕上,再由电脑计算其结果后返回给手机,手机上再根据返回结果模拟触摸/修改准心/修改陀螺仪等方式呈现结果。

内存型外挂其中分类最为之多,总的来说就是要绕过游戏检测读取/修改其内存数据,其中如何绕过游戏检测最为困难,目前相关外挂技术已经发展到实现安卓内核驱动进行内存读写了:

刷入“一次性驱动”

根据安卓内核源码,绕过相关检测后编译出内核驱动,并刷入手机

不过我想说此发展方向对于外挂开发者来说并不完全正确,对于我目前已知的作者技术来说,这无非是投机取巧罢了

在目前来看,反外挂技术暂时领先,虽说外挂技术看似到达了研究系统源码方面,其实不堪一击


我们再来一下浅谈一下实现方法

首先我们要了解一下各个词汇的意思:

游戏基址是保持恒定的两部分内存地址的一部分并提供一个基准点,从这里可以计算一个字节数据的位置。基址伴随着一个加到基上的偏移值来确定信息准确的位置(绝对地址)

Hook钩子,和动态插桩以及蹦床机制差不多,主要是为了能在执行目标函数或指令之前,拦截数据或者执行逻辑,先执行自己插入的一段代码,然后再执行原本的目标函数。完成这个任务的方法有很多,比如可以将要调用的函数地址替换为自己的函数地址,或者在指令流中插入跳转指令使执行逻辑跳转到自己插入的代码块上,等等。不过在修改了原本的数据或指令后,还需要还原以执行原本正常的功能,也就是说在hook时还需要保存原本的现场数据以及指令信息等。
实际上就是在原本的程序执行逻辑中,hook函数获得控制权,并执行我们自定义的功能,然后再将控制权返回原本的逻辑继续执行。形象化可以理解为一条直线在向前走,结果走到了岔路上,走了一会儿又回到了原本的直线方向继续向前。
共享UID:Android系统回为每个应用分配一个唯一的UID,具有相同的UID的应用才能共享数据。两个应用通过ShareUID共享数据,需要相同的ShareUID之外还需要相同的签名才可以。在这种情况下他们可以互相访问私有数据,比如data目录,组件信息等。如果他们跑在同一个进程中,那么他们除了能共享data目录,组件信息,还可以共享内存数据。

内核:
Android是基于linux kernel而开发的,就设备驱动本身的实现而言,与linux的设备没有区别。
所以这也就导致了现在的形式发展成了“内核”
Android不同于一般的嵌入式Linux系统环境固件的组成方式(booloader+kernel+rootfs),其将kernel、ramdisk(rootfs)、second stage(dtb、kernel.logd等)整体打包成一个boot.img文件
我们以rwProcMem33为例(驱动名称:Linux ARM64内核硬件进程内存读写驱动)

image

这是在Github上面的介绍 
项目地址:https://github.com/abcz316/rwProcMem33

它提供了完整的内存读写支持技术

//驱动_打开进程
  uint64_t hProcess = rwDriver.OpenProcess(pid);
  printf("调用驱动 OpenProcess 返回值:%" PRIu64 "\n", hProcess);
  if (!hProcess) {
    printf("调用驱动 OpenProcess 失败\n");
    fflush(stdout);
    return 0;
  }


  //驱动_读取进程内存
  char readBuf[1024] = { 0 };
  size_t real_read = 0;
  //如果是单线程读内存,还可另选用极速版函数:ReadProcessMemory_Fast
  BOOL read_res = rwDriver.ReadProcessMemory(hProcess, (uint64_t)pBuf, &readBuf, sizeof(readBuf), &real_read, FALSE);
  printf("调用驱动 ReadProcessMemory 读取内存地址:%p,返回值:%d,读取到的内容:%s,实际读取大小:%zu\n", pBuf, read_res, readBuf, real_read);

  //驱动_写入进程内存
  memset(readBuf, 0, sizeof(readBuf));
  snprintf(readBuf, sizeof(readBuf), "%s", "写入456");
  size_t real_write = 0;
  //如果是单线程写内存,还可另选用极速版函数:WriteProcessMemory_Fast
  BOOL write_res = rwDriver.WriteProcessMemory(hProcess, (uint64_t)pBuf, &readBuf, sizeof(readBuf), &real_write, FALSE);
  printf("调用驱动 WriteProcessMemory 写入内存地址:%p,返回值:%d,写入的内容:%s,实际写入大小:%zu\n", pBuf, write_res, readBuf, real_write);

  printf("当前缓冲区内容 :%s,当前缓冲区的内存地址:%p\n", szBuf, pBuf);

常见的专用插件

专用插件类外挂,属于定制化外挂,每个外挂只针对一款游戏。

这类外挂的实现顾名思义,是插件形式:利用注入技术将功能模块注入到游戏进程空间中,并执行功能模块入口函数。

在不同的移动设备上,有不同的注入手段。Android平台上的Zygote注入、直接ptrace注入技术;IOS上利用Cydia框架注入dylib。外挂功能模块在被注入到游戏进程后,会执行HOOK操作实现外挂功能。

外挂作者事先需要逆向分析游戏代码逻辑,找到一些游戏功能函数地址,比如说怪物扣血处理函数。然后在外挂功能模块中通过HOOK操作,挂钩相应函数,改写参数或者调用逻辑(多次回调,或者步调用)

。在底层汇编,HOOK操作可以理解为在特定代码地址,增加个跳转指令跳转到外挂作者自定义函数中。目前已经有封装优秀的三方库支持HOOK操作,外挂作者只需要调用相应接口函数,即可实现对指定函数进行HOOK操作,如substrate。


绘制:

还有就是游戏绘制怎么实现的 这个说简单也很简单 说难也就写法麻烦

(以某平为例子)长话短说就是读游戏ue4文件,读游戏世界,然后获取游戏矩阵,读取人物,然后在屏幕画出线条实现

其实说的过于简单点,要读取的数据还有很多,比如自身对象 自身坐标 敌人坐标 自身队伍(需要去除方框(队伍号相同则不显示)) 还需要计算矩阵 阵列偏移 骨骼指针 然后去计算骨骼位置

其实现在大多都使用imgui

ImGUI又称为Dear ImGui,它是与平台无关的C++轻量级跨平台图形界面库,没有任何第三方依赖,可以将ImGUI的源码直接加到项目中使用,也可以编译成dll, ImGUI使用DX或者OpenGL进行界面渲染

速度快是一个很大优点,你所看到的支持高fps刷新的都是使用imgui的


改文件:

其实就是说好听的“破解版”

也许只是这个名称听起来不高级,小学生圈不到米,就有个改文件这个名称

确实有的时候也是字面意思,就比如PUBGM

更改游戏逻辑文件达到作弊效果

逻辑代码:Android平台下逻辑代码的修改,根据游戏引擎不同,改的东西也有所区别。常见的cocos游戏,其逻辑代码保存在so,可通过IDA等工具读取修改ARM、THUMB汇编指令;Unity游戏,其C#脚本代码则是保存在/assets/bin/Data/Managed/Assembly-CSharp.dll中,也可通过ildasm等工具转成IL代码进行修改操作。而在IOS平台下,代码都在app的bin文件中,和Android中的so类似,只需要了解THUMB即可。同样的,还有Lua等代码,根据游戏语言不同改的方式也不同。直接修改汇编指令,可改动空间较小,一般实现是修改跳转、参数赋值。比如死亡判断、通关判断、扣血函数参数修改等。IL、Lua等的修改,则相对较为简单。


直装

其实就是使用共享UID 达到插件与游戏共享数据

只需要修改应用安装包和游戏安装包根目录的xml文件

data/data/XXXX/目录下面的所有数据,因为我们知道这个目录下面的所有数据是一个应用私有的,一般情况下其他应用是没有权限访问的,当然root之后是另外情况,这里就不多说了

比如都加上:

  •  
android:sharedUserId="com.xia0yang">

然后两个应用程序就有了访问权限,可以达到资源共享了

插件就可无root去读取游戏数据了

© 版权声明
THE END
喜欢就支持一下吧
点赞6 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容