首页 > 休闲游戏 > 详情

凌聪:《开心消消乐》如何防玩家作弊

2014年,一款轻度游戏《开心消消乐》在PC端和手机端都获得了很大成功。开发商乐元素在为游戏拥有巨大的用户量和收入开心时,也忙着与作弊玩家“斗智斗勇”。

“10%的用户天天在玩《开心消消乐》,淘宝和百度都有非常多人在卖作弊手段。” 乐元素首席技术官凌冲在MDCC游戏高峰论坛上说,玩家作弊直接影响了游戏的收入,他们累积了许多反玩家作弊的经验,“听我细细道来”。

一、作弊玩家带来的坏影响

1)影响游戏收入;

2)影响游戏平衡。弱联网游戏影响最大的是排行榜,包括全局排名、地区排名和好友排名,如果被作弊,有些用户发现作弊走掉;

3)广告。“它直接骗钱,我们买过一次广告,居然有75%的量是假的。”

  二、可能存在的安全问题

1)存档被篡改和复制,造成你的损失。

2)本地配置被篡改。在离线游戏、休闲游戏里面可能有些配置被篡改掉。

3)帐号被盗和恶意修改。

4)内存被修改。我们有三种内存:传输性内存,因为传输型内存都是一次性的,所以不用加密;永久型内存肯定要加密的,这里放的是用户状态 比如血、精力值;暂存,比如《开心消消乐》打完一关,获取的金币和获取的经验都会暂存的,需要进行加密。

5)网络协议被破解和重放攻击。

6)工程被逆向破译。现在有很多高技术,包括我以前也做过这个事,在CPU广角上直接打几个出来可以反汇编你的代码 ,然后把你的工程逆向。

7)二进制程序可能被修改。刚才讲到的只要涉及到加解密,都会把加解密函数钩走,然后把它修改掉。

8)函数被挂起。

三、存档协议设计

1)Magic number:标记存档类型

2)版本号:标记加密方法类型 。如果一个休闲游戏需要兼容两版本模式肯定需要版本号。

3)源数据。为什么要设计?要验证你解密后的存档数据是不是一致的。

4)初始向量。尽量每次都不要一样,因为否则很容易被反向。

四、密钥的产生

首先,密钥一定是个随机数。第二,密钥最好是生成,不要在代码里面去。比如我们看过一些破解程序,发现密钥直接写在字符串里面。

产生随机密钥的技巧:应使用工业级加密库的产生函数,这样更随机 自己产生的随机数,如以下算法,实际上最多只有231种密钥,而加密算法要求2256。

五、初始向量的用法

尽量不要使用ECB,每一个都是可以单独解的,问题是它的加密强度不够强的,所以我们建议用CBC做加密比较稳妥 。

六、阻止存档转移

1)玩家可能将存档发给他人破解(如淘宝卖家),需阻止设备直接共享存档文件

2)通过使用UDID参与加密,来阻止存档转移

  • 方法1:UDID参与密钥产生
    • KEY = RAWKEY ⊕ SHA256(UDID)
  • 方法2:UDID参与IV产生
    • IV = RAWIV ⊕ SHA256(UDID)

存档协议中只存储RAWIV

当你复制存档 给另外一个设备的时候设备打不开的,因为它的KEY不一样。

七、限制存档降级

“比如我们发现一个版本有漏洞,结果我们打了个过去,用户发现你打了个过去,我赶紧把代码 回滚到以前,然后再打开存档 ,这样的话就可以再次修改,这个就是存档降级。”凌聪说。

1)我们程序里面肯定需要有新旧两个存档的,从旧存档升级到新存档 ,新存档不能给旧程序读取。

2)我们还做了在服务端校验,如果设备里面生了新存档 ,不能再用旧存档 存档 。 防止一个设备上来回存档 的问题。

八、内存修改

“刚才讲了内存修改分三种内存,其中第二、第三种,暂存和永久性内存是必须要加密的。”

凌聪说:“有两个修改期:之前有个八门神器,这就是对比内存 ,内存值变了两次之后,它找到你内存的偏移地址,可以定位到内存地址在哪里。八门神器我们当时解决的方法比较好解决,用非常简单的加减法可以解决加密问题,因为它找不到原来的数据,或者血不是整数,这样它也找不到。现在有一个更高级的,叫烧饼修改器,它能力挺强的,假设你修改的数加了个“038”,它一样可以找到。另外,它支持加减法,如果你的数据是加减法或者乘除法它能找到,所以内存的加密函数需要变化。”

防止内存修改最简单的方式是做一个加密的HashMap ,进的时候是加密的,出的时候是解密的,在函数里面加上一些较为强加密的算法就行了。

九、协议破解的几种可能性

协议破解一种方式是通过抓包工具,移动设备因为支持WiFi,其实挺简单的,现在小米和360WiFi直接插到电脑,把WiFi地址指向小米和360的WiFi,就可以拦它的包了。

抓包完之后,如果你的协议没加密,用户可以伪造请求 ,也可以伪造服务器响应,伪造服务器响应最大的用处是用在APPLE的IEP,IEP会截获一个消息,然后给你一个假的。玩家通过拦截服务器的响应做重放,客户端重放上次的请求。当然,玩家知道协议之后可以伪装成另外一个玩家,这是更恶劣的情节。

十、伪造请求的防范

加密肯定是需要的,加密的通讯协议最好自己写。然后建议AES。

十一、伪造响应的防范 

要么采用非对称签名验证方式防范 ,但是这个速度比较慢,不建议用。

另外一个是用TLS,如果我们要用TLS的话要注意校验服务器的证书在客户端那,因为服务器的证书很容易被篡改 。比如它通讯的时候可以用自己的证书,这样的话是可以拦截你的协议的。如果程序破解了,函数直接就调用了。

十二、重放攻击

“刚才讲的响应服务器主要是不让别人破解我们的协议,重放攻击是什么?”

凌聪说:“重复攻击是我不需要了解你的加密协议,我只需要重放就行了。我们有一个版本的游戏是出现过这样的问题,攻击者拦截你的请求,然后多次重放,如果你没有做校验,很容易导致你的数据不断的往上增加。这个最重要的是支付,比如你从APPLE拿到一个支付响应,回传给你服务器的时候,它抓住这个请求不断的重放,这样很容易造成重放的攻击。”

重放攻击最好的解决方案是中间加一个nonce。服务器的响应,服务器辨别你的时候它要看到,如果这个nonce是以前已经用过的就把它丢弃掉,为啥?因为这肯定是作假。

十三、防范帐号伪装

过程,是登陆的过程。登陆的过程拿到SessionKey,其他所有的请求都要使用这个,这个是服务器端生成的,服务器端可以每次校验这个SessionKey。

“我们是分开的,给用户看Userld,所以我们不要在传输协议仅放一个Userld,这个用户标识是服务器产生的,安全性就没有了,客户端把这个存起来,以后都用这个服务器标识跟后端通讯。”

SessionKey有两个作用,一个是防止多Session登陆,另外,SessionKey和Userld是关联的,因为SessionKey每次都不一样,所以要伪造比较难。为什么不用用户标识?因为每次都传安全性是低的,是很危险的。所以做这两个主要是为了提高你的安全性。

十三、防范程序被逆向破解的方法

1)关键是符号隐藏,函数符号表隐藏住。特别是加解密函数。

2)关键字混淆。

3)程序逻辑混淆。

4)内存加密。

5)阻止动态跟踪调试。

6)二进制程序校验。这里除了你提交的主程序之外,另外一个也要防止篡改。

7)Lua脚本加密也很重要。

十四、符号隐藏

1)尽量不用系统的函数库,因为系统的函数库你没有任何办法把它隐藏 ,它都是暴露在那的,只要你用它,它就可以挂接到钩子上去,所以尽量不要用。

2)重要的函数在模块里面,尽量用static函数。

3)关键加密库要设置关闭符号表导出。你把输出函数符号表隐藏掉。

4)Xcode配置Symbols Hidden By Default。我看国外很多游戏已经这么做了。

5)你可以通过nm命令可以查询到输出函数 。如果没有函数符号表输出就比较安全了。

十五、防范程序被逆向破解的方法

我们现在很多时候只能做到混淆接口、混淆方法名、混淆属性 名,让破解者看不出真正接口的用途 ,这也是一般的JAVA等经常用的混淆的手段。最好的方法是有一些特别的函数,特别加解密汉书尽量用C语言把它包起来,这样比较安全一些。

程序逻辑混淆是以前加密狗做的,但是现在加壳IOS还没有。另外,开源程序逻辑混淆,obfuscator-llvm,大家可以到网上Google一下这个使用方式。

接下来是我们要防止跟踪调试,刚才讲用GDB挂,因为绝大多数人不会做这个事情,我们可以用GDB挂去调它的函数,只要看到有一个数字函数,我就可以看到你的输入输出参数 ,我只要会一点点汇编语言,就基本能看到你的参数 。所以我们需要防止这个GDB,这也是我们参照网上代码怎么把这个东西拦住的。

十六、二进制文件校验

至进制文件校验,如果休闲游戏就在客户端校验。

反盗号,如果离线的话非常容易盗号,越狱机器什么都可以改,所以我们需要防止它做这个事。第一个,最好有个网络帐户,如果用它用网络帐号登陆的话,就不让他用本地帐户校验了。如果是本地校验建议不要用可变的,自己在KeyChain里面存储一个UUID,如果你做越狱了,很可能会丢掉,安卓 上面就自己建一个文件。如果是它用了网络帐户登陆的话,它如果要恢复,比如说它重装了应用的话,可以通过这个网络帐户拿回它的信息,网络帐户有可能是Facebook、QQ、微博甚至自己用户名密码 都是可以的。

解决方案总结:

存档被篡改:AES、限制转移、限制降级 。

协议被破解:AES、SSL/TLS、nonce防重放 。

盗号或用户伪装:用户标识符、社交账号绑定 。

工程被逆向破译:符号隐藏、标识符混淆、逻辑混淆 。

函数被Hook:隐藏和混淆、阻止跟踪调试、阻止外挂启动 。

二进制程序被修改:验证校验码 。

内存被修改:内存加密 。

大招:上传用户操作和随机种子,数据监控+回放+人工审核 。

 

 

QR code