防止多人作弊


10

我几乎完成了一款小型独立式多人游戏的开发。虽然我打算允许人们在单人游戏中作弊,但在多人游戏中这显然是不可接受的。有谁知道有什么方法可以阻止普通的Joe使用Cheat-Engine之类的东西来修改游戏的某些部分?我目前计划让客户端每隔几秒钟将游戏使用的每个设置文件的MD5哈希值(存储为XML)上载到游戏服务器进行验证,但是我能做些什么来阻止内存编辑器等操作。 ?


2
我会推荐这篇文章,《构建多人游戏-安全》,它是为一些多人API编写的,但构想很好并且仍然适用
Cyral,2012年

Answers:


8

如果您担心本地修改的代码,那么如何确定有人没有简单地修改您的通知代码以发送与您期望的相同的MD5哈希的静态列表?实际上,您甚至不需要修改代码就能做到这一点,您只需要一个相当基本的代理即可(假设没有SSL,但即使付出更多的努力也可以伪造)。

做您想要的事情的唯一方法是拥有一台服务器,而根本不信任客户端。所有计算都应在服务器上进行,所有动作至少在某种程度上应得到验证。例如,当您知道他们刚才在另一侧时,请勿让客户说他们想移至地图的一侧。没有中间的服务器去做对游戏至关重要的一切,就不可能没有作弊,因为聪明的人会一直寻找一种方法解决您可以构建到客户端中的所有内容。即使只有其中一种,如果您不考虑通过所有不同的方式来轻微地操纵情况,仍然是可能的。例如,我之前提到的运动验证:如果进行简单的点对点计算,人们仍然可以穿越墙壁。

所以问题是,“平均乔”的平均水平是多少?您已经提到了代码编辑和内存编辑器。这高于我个人认为的平均水平,如果您确实要担心该水平,则需要一个单独的受信任的服务器来完成所有繁重的工作,并且客户端将最终沦为显示和输入设备。


2
@ user185812:通常最好等待至少几个小时,然后标记一个可接受的答案。虽然我个人认为我的答案相当不错(我有偏见),但其他人可能会有更多的投入,而看到一个可以接受的答案通常会阻碍其他人回答。
马修·沙利

@MatthewScharley-不用担心。;)
马丁·索伊卡

11

客户在敌人的手中。(在线世界设计法则

确实,唯一能击败大多数骗子的方法是让客户端成为“瘦客户端”,即:仅充当输入和输出设备,并且从不提供超出其实际需要的更多信息。

这不会停止自动化,也不会停止被动信息的收集和分析,但是您可以设计游戏,使它们不会产生重大影响。

这不会阻止人们通过服务器依赖的格式不正确的消息互相攻击-您的客户端需要防范服务器发出的消息,就像您保护网站免受SQL注入攻击一样。

由于您还希望在单人游戏中使用相同的客户端,因此一种解决方案是在单独的进程/线程中运行本地服务器,并将其在内部作为客户端/服务器设置。然后,“作弊”将在服务器端起作用。我的世界(Minecraft)做了类似的事情,但这绝不是第一个以这种方式从界面分离游戏引擎的游戏。

建议阅读:


2

在基本的多人游戏中,作弊引擎这种作弊根本行不通。客户端仅发送数据以及您设计的数据要执行的操作。通常,这并不比玩家“做”的要多,例如,他朝哪个方向奔跑,如果他在射击等。因此,他对内存所做的更改只会影响自己的游戏,而其他玩家将看不到任何变化,即所谓的不同步。大多数游戏会像这样检测不同步,并从游戏中删除不同步的玩家。

现在还有其他作弊方式,但这些都与游戏的设计方式有关。

为了防止伪造网络消息的最简单的黑客攻击,服务器应检查这些软件包的完整性。“那个家伙刚刚跳了5个屏幕?那不可能,拒绝包裹。” (请注意,您还可以走完全同步的路线-这意味着所有信息都已同步,并且仅“播放器按下了哪些按钮。”这类消息被发送-这使伪造的网络消息在设计上毫无用处。)

在多人游戏中作弊的最后一种方法是可见性破解,那就是修改客户端,以便向玩家显示他不知道的数据。这样的例子没有显示出战争的迷雾,无法看穿墙壁,显示小地图或其他东西。这些是不可能防止的。


我对能见度骇客持不同意见。通过在客户角色知道之前不提供客户信息,是否可以防止这些情况发生?不要误会我的意思,这可能不是一个好的设计。但这不同于无法避免的情况。
xuincherguixe 2012年

@xuincherguixe我认为在某些情况下是不可能的。例如,两个客户端都在相同的IP和相同的端口下播放。在这种情况下,只有客户的良好意愿才能阻止他读取供另一方使用的数据。
Wodzu

1

为了防止基本的骗子引擎操纵变量值,那么您必须隐藏这些值。通常,作弊引擎通过搜索已知变量的已知值,玩更多游戏并使该值变为更改后,Cheat Engine将从先前搜索新值的结果中进行新搜索。这使作弊者可以放大该值的存储位置,现在他们可以使用作弊引擎更改该存储位置的值。

例如,我有245 GOLD ...使用作弊引擎,我搜索245并找到许多内存位置。然后,我再玩一些,将黄金提高到314,然后在先前的搜索输出中搜索值314,并轻松找到存储金的存储位置。

防止这种情况的方法是永远不要将实际值存储在存储位置中。例如,我将值存储在一个对象中,该对象必须在需要时按需计算实际值。假设玩家拥有245 GOLD。如果他们搜索值为245的内存位置,他们可能会发现很多,但没有一个将是实际存储黄金值的存储位置,这是因为您没有存储黄金的值245。当游戏需要知道多少黄金时,它将询问持有该黄金价值的对象,该对象将根据需要进行计算。

因此,现在的问题是:如何以一种不会泄露价值的方式准确地存储价值?这有点棘手和丑陋,我敢肯定有很多方法可以做到。我想做的是存储一个布尔数组(或字节数组)。数组的长度可以是任何长度,但是可以说是13。然后您有一个计数器,表示13变为该实际值的次数。因此,如果我们要表示245,则计数器的值将为18。现在,对于其余的245/13 ...基本上是模数,该数组会将所有布尔值都设置为true。在本例中为11,因此数组中的前11个布尔值将设置为true,其余设置为false。要检索该值,只需将计数器乘以数组长度,然后为每个设置为true的布尔值加1(在第一个false处停止)。现在,数字245永远不会存储在任何地方,并且很难找到需要操纵以更改金币数量的存储位置。创建该对象时,您可能希望将数组长度设置为不同的大小(可能会在某个合理范围内随机选择一个数字)。

编辑:这对于多人游戏和单人游戏很有用。在多人游戏中也有作弊行为,其中数据包中的值可能会更改。这将需要不同的技术来防止,例如对每个数据包进行签名。


1
通常,为了防止作弊,多人游戏会计算服务器上的所有内容,因此修改客户端上的值或发送到服务器的数据包中的值不会改变实际游戏。但是,其余答案仍然很有趣。
Vaillancourt

@AlexandreVaillancourt好点。我担心停滞服务器的CPU计算签名。我想通过仅在两个播放器之间传递数据包来保持服务器快速运行,但是现在您已经指出来,我将仔细看看。
何塞·马丁内斯

如果仅将输入从客户端发送到服务器,则无需签署每个数据包。一旦输入到服务器上,如果输入没有任何意义,它们要么被简单地拒绝,要么被踢出客户端以作弊。服务器计算游戏的下一个状态,然后将新状态发送给所有玩家,这通常是避免作弊的方式(您不会摆脱这样的机器人,但至少要避免玩家随意作弊) 。
Vaillancourt

1
为避免这种情况,您可以让服务器更新新生命,然后将新生命发送给客户端。一切都是在服务器上计算的,并且让客户端成为所有重要事情的“哑终端”:客户端将负责捕获播放器的输入(“在时间T处单击x,y,按钮X在时间T”),将其发送到服务器,并从服务器接收新状态(“玩家现在处于位置X,Y”,“玩家生命ZZZ”)并将其显示给玩家。
Vaillancourt

1
这样,作弊者(中间的人)可以将他们想要的所有信息包弄乱,它不会改变服务器上的游戏状态,因为服务器将确保输入有效(“在最后的0.03秒内在五个不同的位置,这是不正常的,让我们拒绝这些点击”),然后运行所有模拟本身。
Vaillancourt
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.