网络游戏安全之实战FPS游戏CRC检测的对抗与防护

来源:互联网 编辑:wan玩得好手游小编更新:2024-10-29 23:24:19 人气:


本文为看雪论坛精华文章
看雪论坛作者ID:小迪xiaodi



0x00:简介



不得不说,随着时代的发展,游戏产业在近几年的互联网潮流中越来越扮演者重要的地位,与之而来的不仅有网络游戏公司的春天,还有游戏灰色产业的暗流涌动。

在游戏产业的发展中,诞生了一大批所谓的“外x挂”开发人员,他们不断的利用游戏的漏洞,在违法牟利的同时,也促进了游戏安全行业的进步。



同时,在游戏安全的对抗中,诞生了以下几种技术以防止游戏作弊的发生:
⒈ 数据检测:对基础的游戏数据进行校验,例如坐标是否违规越界地图(坐标瞬移功能),人物短时间位移距离是否过大(人物加速功能)等等;
⒉ CRC检测:基于游戏程序代码的检验,例如将人物移动中判断障碍物的je条件跳转修改为jmp强制跳转(人物穿墙功能)等等;
⒊ 封包检测:将游戏数据封包进行校验,防止利用封包漏洞实现违规操作,例如之前的穿X火线强登(可以登录任意账号)等等;
⒋ 机器检测:现在鹅厂 安全组好像换人了 ,游戏机器码封的都挺狠,一封就十年,不过道高一尺,魔高一丈,目前依然不够完善,很多朋友还是可以Pass;
⒌ Call检测:非法调用Call导致校验值非法,例如攻击Call的严格校验(角色扮演游戏自动打怪脚本都是调用Call的)等等;
⒍ 堆栈检测:该检测归于调用Call过程中产生的问题;
⒎ 文件检测:对于游戏本地文件的检测,例如之前穿X火线几年前风靡一时的REZ文件(快刀秒杀,穿墙,遁地,飞天)等等;
⒏ 模块检测:很多外x挂采用“注入”的形式,所以模块检测在游戏安全对抗中也扮演着极其重要的作用;
⒐ 特征检测:这个主要检测典型的使用“易语言”开发的程序,或者部分外x挂市场比较大的毒瘤程序,或者菜单绘制(imgui绘制)等等;
⒑ 调试检测:针对调试器和调试行为的检测,对Ollydbg,CheatEngine等调试器特征和调试行为的检测等;
⒒ 游戏保护:主要是利用R3各种反调试技术以及驱动层的HOOK等技术实现的游戏保护,例如鹅厂的TP等等。

可能还有一些我暂时还没想到的,哥哥们可以在下方补充~



0x01:CRC检测



首先,我们今天要讲的是游戏的CRC检测,所以为了能让下面的内容让大家理解,我们先来准备一下CRC检测的基础知识吧:

⒈ 百度百科给我们CRC的解释

CRC即循环冗余校验码(Cyclic Redundancy Check):是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定。循环冗余检查(CRC)是一种数据传输检错功能,对数据进行多项式计算,并将得到的结果附在帧的后面,接收设备也执行类似的算法,以保证数据传输的正确性和完整性。 

来源:https://baike.baidu.com/item/crc%E6%A0%A1%E9%AA%8C

⒉ 维基百科给我们CRC的解释

循环冗余校验(英语:Cyclic redundancy check,通称“CRC”)是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种散列函数,主要用来检测或校验数据传输或者保存后可能出现的错误。生成的数字在传输或者存储之前计算出来并且附加到数据后面,然后接收方进行检验确定数据是否发生变化。一般来说,循环冗余校验的值都是32位的整数。由于本函数易于用二进制的计算机硬件使用、容易进行数学分析并且尤其善于检测传输通道干扰引起的错误,因此获得广泛应用。此方法是由W. Wesley Peterson于1961年发表[1]。

来源:https://zh.wikipedia.org/wiki/%E5%BE%AA%E7%92%B0%E5%86%97%E9%A4%98%E6%A0%A1%E9%A9%97


我们总结一下上面的百科解释:CRC是一种校验算法并且该算法被广泛应用于文件,数据等的校验。

不过好像对于逆向来说还是有些模糊,那么现在就让我们打开看雪论坛发布的《加密与解密(第四版)》第279页,看一下其中的解释:




通过翻阅书籍,我们发现实际上CRC算法有很多种,而我们运用在软件加密中的CRC算法为CRC32算法。

哇,这本书,兄弟萌,你们看,这本书,简直就是逆向界的圣经啊,别犹豫了!买他!书本有价!知识无价!

哈哈,开个玩笑,在这里对所有参与《加密与解密》书籍工作的朋友致敬!



0x02:手写一个CRC检测



参考《加密与解密》书籍,我们便写如下代码,实现我们的CRC检测:



首先,为了方便我们进行学习,我们将CRC算法运用于自己身上,检验自身代码是否被修改,整体性代码如下:

#include
#include


int crc = NULL;
int have_crc_table = NULL;
unsigned int crc32_table[256];

//生成具有256个元素的CRC32表
void Crc_Make_Table()
{
have_crc_table = 1;

for (int i = 0; i 256; i++)
{
crc = i;
for (int j = 0; j 8; j++)
{
if (crc & 1)
crc = (crc >> 1) ^ 0xEDB88320; //CRC32 多项式的值,也可以是0x04C11DB7
else
crc >>= 1;
}
crc32_table[i] = crc; //生成并存储CRC32数据表
}
}

//根据CRC32数据表计算内存或文件CRC校验码
unsigned int Calc_Crc32(unsigned int crc, char *Data, int len)
{
crc = 0xFFFFFFFF; //将CRC初始化为-1

//判断CRC32表是否生成
if (!have_crc_table)
Crc_Make_Table();

for (int i = 0; i {
crc = (crc >> 8) ^ crc32_table[(crc ^ Data[i]) & 0xff];
}
return ~crc;
}

int main()
{
SetConsoleTitleA("Crc检测过掉学习工具 Ver1.0 提供方:小迪Xiaodi");

printf(" ");

printf("使用CE工具->添加地址0x402000->查找访问并尝试过掉检测! ");

printf("如果修改主程序模块,将会提示 “CRC代码校验检测到您修改了代码!”: ");

//初始内存校验值
unsigned int uMainMoudleSumA = Calc_Crc32(0, (char*)0x400000, 0x1F000);//400000- 41D000


//while循环开启CRC检测
while (1)
{
//CRC循环检测内存实时校验值
unsigned int TmpCrcSum = Calc_Crc32(0, (char*)0x400000, 0x1F000);

if (TmpCrcSum != uMainMoudleSumA)
{
//封号处理-掉线处理
MessageBoxA(NULL, "CRC代码校验检测到您修改了代码!", "Caption", MB_OK);
}

//为了方便,我在这里使用的Sleep函数控制检测的周期
Sleep(2000);
}

getchar();
return 0;
}


最后,我们在生成文件的时候,要注意以下几个问题:

⒈ 静态编译和去除优化等的设置






⒉ CRC校验函数传入参数的设置:

代码处:
//计算内存校验值
Calc_Crc32(0, (char*)0x400000, 0x1F000);

在这里尤其要注意传入的第三个参数,他代表了一个校验的范围,那么这个位置,我们如何确定呢?

①:先编译生成文件,我生成的是Release版本:




②:用PE相关的工具确定程序主模块镜像的大小,在这里我使用的是PEID v0.95工具:



复制粘贴一下镜像大小,传入一下就可以了,这个参数不可以乱填,否则会造成数据溢出,导致程序崩溃。


0x03:对自己的CRC程序的防护测试



⒈ 运行自己的程序并用CheatEngine添加地址:




⒉ 修改代码测试

由于0x00402000处于代码段的位置,所以我们修改数值就相当于修改了代码,也就相应的触发了代码CRC的校验



⒊ 我们将末尾的数字“2”改为“3” ,直接触发了CRC检测:




0x04:对自己的CRC程序的分析



① 首先,在攻击前,我们要知道代码的CRC检测是针对代码段的;
② 代码段是用来执行的,正常情况下不会有其他数据访问代码段,被访问的大多是数据段,代码段被访问,很可疑就是CRC检测;
③ 此处说的“访问”的概念,大家可以通过CheatEngine工具中的“找出是什么访问了这个地址”来理解。
开干!



⒈ 针对0x402000这个地址,在CheatEngine工具中鼠标右键,查找访问,操作如下:



2.检测出现了!




我们记录一下该处的访问代码:
0040103F - movsx ecx,byte ptr [eax]

因为Ollydbg的调试体验要更好一些,所以我们记录地址:0x40103F,并转到Ollydbg去分析:



Ollydbg舒服就舒服在还能把你的代码分析出来,太强了!



⒊ 下断走一遍流程


更多...

相关文章