Creator 3.x 资源加密方案!支持Web与原生

引言:在10月29日 Cocos Star Meeings 上海站上,羽毛先生分享了 3.x 资源加密与自定义一键打包相关方案,本文为分享内容的文字版。

资源加密是保障项目安全的重要一环。本次和大家分享一个资源加密与解密的完整方案,能够支持多平台的资源加密与解密功能,有效保护资源,增加破解难度。

本方案基于 Cocos Creator 3.x,测试基于 3.5.2,框架机制上可以拓展支持图片、文本等多种资源类型的加解密。限于时间,目前实现支持 png 资源,本次也使用 png 资源进行说明,对其他资源类型的支持将陆续补充与完善。下载地址见文末。

需求

Cocos Creator 打包产生的包体默认对图片、文本等资源是不加密的,因此如果想要获取游戏的包体的资源,是轻而易举的。

例如对于 apk 包体,只需要对包体解压,即可非常轻松地获得资源。

180a59068a8539c7e0911c2daa16d817.png

5273df1df5997dfc4fde67f6696c8241.png

对资源进行加密,能够提高破解的门槛,使得他人获取资源“不那么容易”。但因运行环境在本地,无法完全防止破解,加密本质上是与破解者之间的博弈,尽可能提高破解者的成本。

破解基本原理

初级破解玩家:

  1. 解压包体,提取游戏 asset,获取所有资源。

  2. 如果资源有加密,则尝试寻找市面上已有的解密工具进行尝试,如果失败遂放弃。

中级破解玩家:

  1. 解压包体,提取游戏 asset,获取所有资源。

  2. 如果资源有加密,则寻找市面上已有的解密工具进行尝试。

  3. 现成工具无法完成解密,通过内存地址跟踪获取密钥,通过反汇编等手段找到解密方法,手动编写解密工具或者脚本进行批量解密,或者想办法利用现有代码。

高级破解玩家:

  1. 解压包体,提取游戏 asset,获取所有资源。

  2. 如果资源有加密,则寻找市面上已有的解密工具进行尝试。

  3. 现成工具无法完成解密,通过内存地址跟踪获取密钥,通过反汇编等手段找到解密方法,手动编写解密工具或者脚本进行批量解密,或者想办法利用汇编代码。

  4. 解密还原 JS 代码,改写代码,换皮,上线流通。

对策

针对初级、中级、高级破解玩家,简单的加解密方法:

1. 远程加载资源并设置 token 验证,该方法不算为真正的加密方法,但也可以阻挡只会解包体的破解玩家。某些资源可以等到需要使用的时候再加载,迫使破解者通关才可获取资源,提高破解者获取资源的时间成本。

2. 对资源进行去除文件头、文件尾后,进行加密。游戏运行读取资源时,再进行解密,因该过程需要进行运算,会使得资源加载时间有所延长。

可以采取偏移运算、异或运算或多种运算组合;也可以采取AES加密运算等其他的凯撒密码加密方法(摘要算法,不可还原,主要用于身份验证),但会导致更长的加载时间。

Q:为什么要“去除文件头、文件尾后”?

A:压缩体积(实际上深入研究 png,还有一些冗余数据块可以去掉),与改变后缀名配合使用,混乱资源,破解者需要反编译代码找回后缀对应关系,编写代码还原文件头,增加破解成本,同时开发者也增加了维护成本,但其实作为通用库维护,成本也算还好。

3. 另外可以采取网络获取密钥、多变量拼接密钥等方式增加破解者获取密钥的难度,通过代码混淆的方式增加破解者理解解密算法的成本。

加密的实现

c2c88c9812ffb89d6c8f8856cff5a9d5.png

上图所展示的自定义加密方法是:

  1. 偏移。

  2. 异或。

  3. 第一点与第二点组合。

  4. AES、DES 等凯撒加密方法(运算量相对前几种更大一些,解密 CPU 消耗高,对加载时长的影响更明显)。

首先遍历资源文件:

94c1a65f7faabe06e088353fcff3eefc.png

目标文件类型判断、判断是否已加密,防止重复加密:

6fc24ba74f94ec1d8872d56b8a1be074.png

类型文件特殊处理,可选择进行冗余数据块去除:

327b086b6d049ab61f9788e9805062d8.png

进行资源加密并重新写入数据:

96b0e535103f815d39b76d5f99222f4f.png

加密结果:

3b3536797939de7e284dacee16bd0267.png

进行加密后,即使进行解包,获取的资源文件也无法直接使用,必须获得密钥及解密方法后,编写解密工具进行批量解密后才可完成破解。

08ec716be3a84a9d871b490f26ce6d0d.png

解密的方法

对资源进行加密后,在游戏内直接读取资源,则无法解析,需要根据对应的加密密钥与加密方法,编写对应的解密流程进行解析后方可使用。

解密过程基本与加密过程对称,关键点在于定位程序读取文件数据的代码位置,改造代码,将数据还原为加密前的状态。同时支持保留未加密资源的加载,不影响未加密资源的加载。

a8d15184c0caaea07e196e4a4a4e63f7.png

加载流程解析

对解密流程有了基本的认识后,下面就来研究如何在引擎的资源加载流程中增加解密流程,对加密后的资源进行解析。

b1a211cf6f99e4edad80e2e9480af936.png

824667f1cdb91e5c11737b1dfc6a2ffe.png

93d4c12e3838a5b3b71d01ff15737c0d.png

5d2f1932371348beb5c24320400a7df5.png

fa6facf4054a9e7deec34446ce3df124.png

通过对引擎代码的跟踪,我们发现所有的资源加载操作,都将进入管线,由管线完成加载的流程。

翻看官方文档关于管线的内容:

6ae0daf82c16885efc8bd8d3fbe24126.png

8b214bd1619dab900bbcb6b91e37a134.png

根据文档进一步跟踪到下载与解析的文档,发现可以使用文件类型自定义处理方法,我们可以利用这点功能实现解密流程的接入。这里只演示 png 资源的流程,更多资源后续加入。

d11953c86e22b7fed1fae4404a30c2d8.png

Web 端实现

因为启动流程的脚本加载顺序如下:

  1. Cocos 引擎

  2. 插件脚本

  3. 普通脚本

因为 Cocos 编译后的工程或者包体,资源文件名无规则,所以场景资源等也会被加密脚本统一加密。而场景资源等又不便于控制加载流程。

因此将注册代码作为插件代码加入到引擎工程中,可以实现早于资源加载完成注册,避免加载失败。

3013fa666df7e3ee4596cd6ed00e4345.png

导入插件代码后,在代码文件中,参照文档进行下载器的注册,这里的代码与引擎代码基本一致,只是将下载图片的代码进行了改造。对于图片资源,通过arraybuffer下载后,转换为base64进行显示。

const downloadImage = (url, options, onComplete) => {    const func = cc.sys.hasFeature(cc.sys.Feature.IMAGE_BITMAP) && cc.assetManager.allowImageBitmap ? cc.assetManager.downloader.downloadBlob : downloadImageByBuffer;    func(url, options, onComplete);}const downloadImageByBuffer = (url, options, onComplete) => {    console.debug("downloadImageByBuffer:" + url);    downloadArrayBuffer(url, options, function (err, data) {        if (err) {            onComplete && onComplete(null, data);            return;        }        if (checkIsEncripted(data, ENCRYPT_SIGN)) {            let index = url.lastIndexOf(".");            let suffix = url.substr(index + 1);            let typeStr = imgTypes[suffix] || imgTypes["png"];            data = decodeArrayBuffer(data, ENCRYPT_SIGN, ENCRYPT_KEY);            let base64code = arrayBufferToBase64Img(data);            base64code = `data:${typeStr};base64,${base64code}`            cc.assetManager.downloader.downloadDomImage(base64code, options, onComplete);        }        else {            cc.assetManager.downloader.downloadDomImage(url, options, onComplete);        }    })}

a08f885e048fd13baf3f812785b75fbf.png

因为引擎对导入的插件代码没有进行加密,因此还需要对插件代码进行混淆则更为安全,提高破解者的成本。这部分内容将在 demo 中体现。

原生端实现

afac18332bf9e92de6502dc71fb9528a.png

8209e3f2b9561456028d477b4cc5d5c7.png

5047b104dabd11b37c8aebaa5cef63d3.png

跟踪代码可发现,在原生端,资源的加载基本都会经过 getStringFromFile()与getDataFromFile() 方法,因此在这两个方法中进行解密,可以满足大多数的资源解密需求,在 C++ 中进行处理,效率也将更高,对加载的影响也可以降低一些。

至此,简单的加密流程已经结束。

其他的加强内容:

  1. 代码混淆,提高查看解密方法的成本,这一点,3.x 提供了脚本加密的方式,也能提高一定的安全性。

  2. 加密密钥不采取本地明文,使用启动时网络获取,提高获取密钥的成本。

  3. 密钥采用多地址存储,提高调试成本。

  4. 图片隐藏水印,保留法律追溯的途径。

  5. 防改包重新上线:启动或不定时进行签名验证,采取上报后台措施或不定时 FC。

adb9f8b148130842516dba4898b7fcca.png

签名验证参考文章:

https://blog.csdn.net/zhu6201976/article/details/113915351

小结

以上是在 web/native 等不同平台的资源加解密方案,因为加密是在打包时一次完成,因此密钥与加密方法都是固定的,加上运行环境在用户手中,高级破解玩家如果原因耗费大量的时间进行破解,理论上也是可以拿到密钥与解密方法,无法完全防止破解。

但是随着加密手段的加强,能够逐渐增加破解者的破解成本,继而能够劝退很大一部分破解者,本质上是与破解者的“博弈”。

以上是羽毛对资源加密的理解,理解有误的地方欢迎大家纠错与交流。

资源下载

  • web/native 资源加密工具与 demo 下载

https://store.cocos.com/app/detail/4201

往期精彩

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值