首页
社区
课程
招聘
[原创]网络游戏安全之实战某游戏厂商FPS游戏CRC检测的对抗与防护
发表于: 2019-8-3 02:19 27550

[原创]网络游戏安全之实战某游戏厂商FPS游戏CRC检测的对抗与防护

2019-8-3 02:19
27550

——————————————————————————————————————————————————————————————————


——————————————————————————————————————————————————————————————————



——————————————————————————————————————————————————————————————————

不得不说,随着时代的发展,游戏产业在近几年的互联网潮流中越来越扮演者重要的地位,与之而来的不仅有网络游戏公司的春天,还有游戏灰色产业的暗流涌动。在游戏产业的发展中,诞生了一大批所谓的“外x挂”开发人员,他们不断的利用游戏的漏洞,在违法牟利的同时,也促进了游戏安全行业的进步。



同时,在游戏安全的对抗中,诞生了以下几种技术以防止游戏作弊的发生:

⒈数据检测:对基础的游戏数据进行校验,例如坐标是否违规越界地图(坐标瞬移功能),人物短时间位移距离是否过大(人物加速功能)等等

⒉CRC检测:基于游戏程序代码的检验,例如将人物移动中判断障碍物的je条件跳转修改为jmp强制跳转(人物穿墙功能)等等

⒊封包检测:将游戏数据封包进行校验,防止利用封包漏洞实现违规操作,例如之前的穿X火线强登(可以登录任意账号)等等

⒋机器检测:现在鹅厂 安全组好像换人了 ,游戏机器码封的都挺狠,一封就十年,不过道高一尺,魔高一丈,目前依然不够完善,很多朋友还是可以Pass

⒌Call检测:非法调用Call导致校验值非法,例如攻击Call的严格校验(角色扮演游戏自动打怪脚本都是调用Call的)等等

⒍堆栈检测:该检测归于调用Call过程中产生的问题

⒎文件检测:对于游戏本地文件的检测,例如之前穿X火线几年前风靡一时的REZ文件(快刀秒杀,穿墙,遁地,飞天)等等

⒏模块检测:很多外x挂采用“注入”的形式,所以模块检测在游戏安全对抗中也扮演着极其重要的作用

⒐特征检测:这个主要检测典型的使用“易语言”开发的程序,或者部分外x挂市场比较大的毒瘤程序,或者菜单绘制(imgui绘制)等等

⒑调试检测:针对调试器和调试行为的检测,对Ollydbg,CheatEngine等调试器特征和调试行为的检测等。

⒒游戏保护:主要是利用R3各种反调试技术以及驱动层的HOOK等技术实现的游戏保护,例如鹅厂的TP等等

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





——————————————————————————————————————————————————————————————————

首先,我们今天要讲的是游戏的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)是一种数据传输检错功能,对数据进行多项式计算,并将得到的结果附在帧的后面,接收设备也执行类似的算法,以保证数据传输的正确性和完整性。

来源: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

循环冗余校验(英语: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检测:


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

#include <Windows.h>
#include <stdio.h>


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 < len; i++)
	{
		crc = (crc >> 8) ^ crc32_table[(crc ^ Data[i]) & 0xff];
	}
	return ~crc;
}

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

	printf("\n\n");

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

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

	//初始内存校验值
	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;
}


#include <Windows.h>
#include <stdio.h>


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 < len; i++)
	{
		crc = (crc >> 8) ^ crc32_table[(crc ^ Data[i]) & 0xff];
	}
	return ~crc;
}

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

	printf("\n\n");

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

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

	//初始内存校验值
	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);

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

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

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



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




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

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


——————————————————————————————————————————————————————————————————

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




——————————————————————————————————————————————————————————————————

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


⒉修改代码测试:

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



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



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


——————————————————————————————————————————————————————————————————

①首先,在攻击前,我们要知道代码的CRC检测是针对代码段的

②代码段是用来执行的,正常情况下不会有其他数据访问代码段,被访问的大多是数据段,代码段被访问,很可疑就是CRC检测

③此处说的“访问”的概念,大家可以通过CheatEngine工具中的“找出是什么访问了这个地址”来理解

开干!



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





——————————————————————————————————————————————————————————————————

①首先,在攻击前,我们要知道代码的CRC检测是针对代码段的

②代码段是用来执行的,正常情况下不会有其他数据访问代码段,被访问的大多是数据段,代码段被访问,很可疑就是CRC检测

③此处说的“访问”的概念,大家可以通过CheatEngine工具中的“找出是什么访问了这个地址”来理解

开干!



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



2.检测出现了!



我们记录一下该处的访问代码:

0040103F - movsx ecx,byte ptr [eax]

0040103F - movsx ecx,byte ptr [eax]

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



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



⒊下断走一遍流程

刚开始的时候,注意观察eax:



单步往下执行,下面会有个强制性的向上跳转:



继续执行走到初始位置:



总结:发现eax由0x400000变成了0x400001,也就是说,它在循环的递增检测所有范围内的内存代码数据

⒋返回上一层观查一下函数

通常,大家可能会CTRL+F9返回上一层,或者按如下图中返回: 



这样做后就发现无论如何都无法返回,那应该怎样做呢?

很简单,我们可以从堆栈中返回,堆栈窗口有个神奇的功能就是返回数据:



对着“返回到”敲下回车键,抽个烟的时间:



奇迹竟然发生了:



最后于 2019-8-13 12:12 被小迪xiaodi编辑 ,原因:
上传的附件:
收藏
免费 22
支持
分享
打赏 + 1.00雪花
打赏次数 1 雪花 + 1.00
 
赞赏  mb_ovrzbwwl   +1.00 2019/08/07 有事找你处理,如果有时间请加Q7620971,给报酬!!!
最新回复 (47)
雪    币: 5836
活跃值: (1903)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
2

检测没了,死的透透的,睡觉睡觉





QQ交流群:786070465,大家可以一起学习交流心得经验
最后于 2019-8-13 12:14 被小迪xiaodi编辑 ,原因:
2019-8-3 02:22
0
雪    币: 7784
活跃值: (2179)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
娓娓道来,很是舒服
2019-8-3 11:10
1
雪    币: 5836
活跃值: (1903)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
4
friendanx 娓娓道来,很是舒服[em_63]
感谢老哥的点评,会继续提高文章含量和文笔质量的!
2019-8-3 11:38
0
雪    币: 2316
活跃值: (4732)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
模拟器搜到的游戏数据下不了硬件断点啊
2019-8-3 11:53
0
雪    币: 36
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
娓娓道来,我一个电科的都能看懂计算机的东西了,赶忙来支持老哥一下
2019-8-3 13:04
0
雪    币: 495
活跃值: (147)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
7
娓娓道来,我一个电科的都能看懂计算机的东西了,赶忙来支持老哥一下
2019-8-3 15:59
1
雪    币: 1479
活跃值: (155)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
大佬牛逼!
2019-8-3 17:05
1
雪    币: 128
活跃值: (169)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
真棒啊 学习了好多东西 对crc有了新见
2019-8-3 22:15
0
雪    币: 6124
活跃值: (4581)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
10
这个CRC32还是有点东西,说句实话CRC的检测手段也只能是这样了,网游再难点也就是 CRC上CRC->CRC+VM->自写类数据校验算法。所以现在都在研究其它更隐蔽的、不在客户端上的方案。当然,CRC检测的地位还是很重要的。
2019-8-4 00:40
0
雪    币: 297
活跃值: (18)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
就是干
2019-8-5 01:37
0
雪    币: 7552
活跃值: (2627)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
12
现在5G开始进入生活,在将来,会不会把本地文件都放在服务器上,CRC校验也只在服务器中进行呢?
2019-8-5 09:27
0
雪    币: 8
活跃值: (58)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
13
可以
2019-8-5 10:54
0
雪    币: 200
活跃值: (555)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
14
放服务器还需要啥子crc额 啥保护都不需要也行啊
2019-8-5 11:00
0
雪    币: 17
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
15
老哥,我是个小白,之前请老外帮我用C++做了一个软件,源代码发过来了。但是我看不懂。钱也给了他到底值不值当时花的钱我也不确定,求大佬帮忙查看一下2330125017@QQ.COM
2019-8-7 01:02
0
雪    币: 8395
活跃值: (4951)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
16
pghuanghui 现在5G开始进入生活,在将来,会不会把本地文件都放在服务器上,CRC校验也只在服务器中进行呢?
逻辑都在服务器上了还校验什么,厂商把所有计算放在服务器上的成本太大,还不如拿出个零头好好搞一个反作弊,再说了,服务器也没法完美解决外挂,按键脚本,找色这类的不说,也有玩家自己心态有问题,自己被打死了那一定是挂
2019-8-8 12:33
0
雪    币: 5836
活跃值: (1903)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
17
pghuanghui 现在5G开始进入生活,在将来,会不会把本地文件都放在服务器上,CRC校验也只在服务器中进行呢?
想法可以,网速可能也足以实现,但是成本较大...
2019-8-8 12:35
0
雪    币: 917
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
18
希望楼主出更多的教学
2019-8-9 22:13
0
雪    币: 5836
活跃值: (1903)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
19
来啦老弟 希望楼主出更多的教学
来了老弟?
2019-8-9 22:36
0
雪    币: 127
能力值: (RANK:0 )
在线值:
发帖
回帖
粉丝
22
汇编指令打码,字节码不打码,你认真的吗?
2019-8-13 03:25
0
雪    币: 204
活跃值: (80)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
认真的,哈哈哈,我也发现了。
2019-8-13 08:14
0
雪    币: 142
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
大佬牛逼!
2019-8-13 08:48
0
雪    币: 1328
活跃值: (47)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
emmm....很细腻
2019-8-14 15:43
0
游客
登录 | 注册 方可回帖
返回
//