12558网页游戏私服论坛

 找回密码
 立即注册
游戏开服表 申请开服
游戏名称 游戏描述 开服状态 游戏福利 运营商 游戏链接
攻城掠地-仿官 全新玩法,觉醒武将,觉醒技能 每周新区 经典复古版本,长久稳定 进入游戏
巅峰新版攻 攻城掠地公益服 攻城掠地SF 新兵种、新武将(兵种) 进入游戏
攻城掠地公 散人玩家的天堂 新开 进入游戏
改版攻城掠 上线即可国战PK 稳定新区 全新改版,功能强大 进入游戏
少年江山 高福利高爆率 刚开一秒 江湖水落潜蛟龙 进入游戏
太古封魔录 开服送10亿钻石 福利多多 不用充钱也可升级 进入游戏
神魔之道 签到送元宝 稳定开新区 送豪华签到奖励 进入游戏
神奇三国 统帅三军,招揽名将 免费玩新区 激情国战,征战四方 进入游戏
龙符 三日豪礼领到爽 天天开新区 助你征战无双 进入游戏
王者之师 免费领豪华奖励 免费玩新区 6元送6888元宝 进入游戏
查看: 262|回复: 0

游戏检测的对抗与防护艺术

[复制链接]

60

主题

60

帖子

130

积分

实习版主

Rank: 7Rank: 7Rank: 7

积分
130
发表于 2021-7-18 17:56:07 | 显示全部楼层 |阅读模式
[toc]
媒介

从游戏外挂的利用角度来看,外挂的举动无非有如下两种:

  • 修改游戏的关键数据和代码:属于篡改举动
  • call游戏函数:属于未授权访问举动
游戏设计者针对这两种举动产生了无数的防护机制。然而道高一尺魔高一尺,逆向职员也根据游戏内的反外挂机制衍生出了相应的对抗手段。
本日我们就来聊一聊所谓的游戏检测对抗与防护。本次用于实验的游戏的老版本的口袋西游。
首先我们需要先找到游戏中的一个功能call,通过这个call来进行游戏检测的对抗与防护
通过send函数定位吃药call

在Windows网络编程中,send函数和WSASend函数都是ws_32.dll的导出函数,主要负责发送数据包。网络游戏客户端要与服务器通讯,必须调用send函数。
只要在send函数下断,然后进行堆栈回溯分析,就能准确定位关键函数的调用链。在这条链上,进行排查就能得到想要的功能call

随便吃一个药品,这里记下药品的位置是在第22格。此时游戏断下

在这个地方下个断点 让程序断下,这个call只需要分析一个参数就是edx
edx的值是0x15,也就是十进制的21。药品的位置在第22格,假如从0开始计数的话,那么这个参数大概就是药品的位置了。

但是当我们点击吃药call的时候会弹出一个警告框。这样就构造了一个call的检测(吃药call参数写死了,记得把药品放到第一个格子)
处理变量检测

call的检测原理

当我们正常在游戏中吃药是没有检测的,那是因为我们完完整整的把游戏的代码全部调用了;而我们直接点吃药call的时候执行的代码是不完全的。
那么游戏的开发者就可以在吃药call的外层设置一个变量,并且给变量赋值,然后在吃药call内层的某一个位置对这个变量的值进行检测。假如值不对,说明代码没有被完全执行。
在检测完成之后,再修改这个变量的值到原始状态,然后进行下一次检测。整个流程的伪代码如下:
//用于检测的全局变量int status=0;function(){    //调用其他代码...........    status=1;    吃药call();     //调用其他代码...........}吃药call(){     //调用其他代码...........    if(status==1)    {        //正常执行代码    }    else    {        //检测到外挂 进行处理    }    //再对status进行赋初始值 以便进行下一次检测    status=0;     //调用其他代码...........}查找检测变量

这个变量的值其实就相当于一个标志位,0和1的大概性比较大。所以我们可以通过搜索0和1的方式来找到这个变量,假如不行再尝试未知的初始值。

我们在CE里扫描1。然后F9运行程序,这个时候吃药call执行完毕,检测标志位也被规复到原始状态

一直重复这个过程,末了剩下十个左右的地址就可以停止搜索了。

第一次断下的位置,[68EB2374]这个地址会被赋值为1,F9运行程序

第二种就是在调用call的时候,将检测变量赋值为正常调用call时候的数值。
堆栈检测

变量检测有一个很明显的缺点,就是需要一个实时去修改一个全局变量,这种方法很容易用CE搜索到。那么能不能通过其他方式去传递检测变量而又不被CE扫描到呢?答案是可以。这个就是堆栈检测。
堆栈检测原理 基于本地

堆栈检测的基本原理就是检测堆栈中的返回地址。假如游戏中一个正常的call被执行的话,那么堆栈中的全部的返回地址一定是本模块的;
正常调用吃药call堆栈地址如图:

基于这个特点,程序只要在功能call内部去读特定的堆栈返回地址,检测返回地址是否属于本模块,就可以检测出当前的功能call是否被非法调用。
堆栈检测原理 基于服务器

别的一种情况比较少见,程序会通过一个参数将当前堆栈的一部分数据发送到服务器,服务器吸收到这些数据以后,再对参数内的堆栈地址进行检测。
这种方式不太实用,首先发送这部分堆栈数据很容易被调用者发现,其次会增大服务器压力,所以这种检测方式相对比较少见。
处理一层堆栈检测

这种检测的处理方法也有两种,第一种单步跟找到这个堆栈检测call,处理掉。但是这种检测call大概处在代码的任何一个位置,找起来不是那么容易。
第二种就是修改我们自己的程序代码。首先在进入call之后将返回地址修改为游戏模块内正确返回地址,过掉检测call。然后在脱离call之前将返回地址修改为我们自己的返回地址,包管游戏正常执行。其实就是写两个HOOK修改堆栈地址。
伪代码如下:
HOOK函数头(){    //生存原程序的返回地址    mov g_retaddr,[esp];    //修改返回地址为游戏内的返回地址    mov [esp],0x12345678}HOOK函数尾(){    //修改返回地址为原程序返回地址    mov [esp],g_retaddr;}处理多层堆栈检测

假如堆栈检测只检测一层返回地址的话,那么就可以用上面的方式过掉检测。但是游戏往往会检测堆栈内的多个返回地址。
多层堆栈检测处理也很简单。处理一层堆栈检测要用HOOK的方式是因为在调用游戏内部的功能call的时候,我们没有办法去修改这个call内部的代码。
但假如是多层堆栈检测,就可以在调用这个功能call之前,就布局好当前的堆栈返回地址。伪代码如下:
function(){    sub esp,0x28;    //修改第一层返回地址    mov [esp],0x12345678;    //修改第二层返回地址    mov [esp+0x14],0x66666666;    //调用功能call    call xxxxxxx;    //还原堆栈    add esp,0x28;}利用上面这种方式,不管游戏内部检测多少层堆栈返回地址,我们都可以通过直接伪造堆栈的方式达到过掉检测的目标。
CRC检测

什么是CRC检测

上述的两种方式都是对call游戏函数的未授权访问举动进行对抗防护,而CRC检测是为了防止修改游戏的关键代码的篡改举动进行防护的手段。
事实上,修改游戏代码是很容易被检测到的,只要给代码段加一个校验功能,提前盘算好整个代码段的CRC值,然后单独开一个线程,循环盘算CRC并且比对之前预先生存的值,假如值不相等,说明代码段被修改。
构造CRC检测


然后到吃药call的位置,在这个地方下一个断点,软件断点会将当前汇编前两个字节修改为0xCC,也就等于是修改了代码段

在吃药call下一个内存访问断点,游戏断下

开启数据检测

这里有两条代码在实时访问血量地址。单从模块的角度很快就能看出第二条代码不是在游戏的主模块,假如从模块看不出来的话就只能挨个分析了。
处理方式和代码检测相同,定位到检测代码以后,对数据大概代码进行修改即可。这里不再重复。
总结

末了对以上几种检测的对抗与防护进行简单总结:

  • call游戏函数的未授权访问举动检测——变量检测:利用CE搜索出检测标志位进行修改
  • call游戏函数的未授权访问举动检测——堆栈检测:利用HOOK和内联汇编的方式伪造堆栈
  • 修改游戏的关键代码的篡改举动检测——CRC检测:利用访问关系下内存断点定位到检测代码进行处理
  • 修改游戏的关键数据的篡改举动检测——数据检测:利用访问关系下内存断点定位到检测代码以后,排查处理

来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
楼主热帖
回复

使用道具 举报

*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|12558网页游戏私服论坛 |网站地图

GMT+8, 2024-4-29 07:57 , Processed in 0.125000 second(s), 31 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表