Unity小贴士 导出资源文件和简单加密方式

原创文章,转载请注明出处。


记得当初开发手游时,在看到了各类软件对IL的强大反编译功能和disunity的解包能力后,跟我同一个组的师兄不禁发出了感叹,“有种不穿衣服走在大街上的感觉”。


可以相信这世界上没有贼,但是却不能不给房间上锁。虽说即使有了锁,有心人仍然能花功夫进来——混淆就有反混淆,加壳就有脱壳,加密还能破解。有许多人以此为乐。但是随着安全手段的增多,破解难度和时间成本也会呈几何级数上升,自然就失去了让人破解的经济意义。


本文要讨论的是Unity资源文件的加密方式。对代码的保护可以参考雨松momo的关于代码混淆的文章:http://www.xuanyusong.com/archives/2664。如果嫌力度不够,还可以对dex加壳,对so加壳等,这里不赘述。


现如今AssetBundle的文件组织方式、压缩算法等已经成了半公开的知识,disunity作为一个开源项目更是成了广大U3D程序员的必备工具。仅仅是因为disunity就不使用AssetBundle显然是因噎废食,因此资源文件的加密某种意义上就是防止AssetBundle被disunity解包。


为了对AssetBundle进行加密,可以分这样两步:


一:和平常一样导出AssetBundle。这个的网上代码有很多。

二:运行一个外置的工具对AssetBundle进行加密。这里贴一个例子。


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace Encyption
{
    class Program
    {
        //157即二进制的10011101,原AssetBundle中每一位都与之进行半加。
        const Byte key = 157;

        static void Main(string[] args)
        {
            string str = System.Environment.CurrentDirectory;
            string[] ABs = Directory.GetFiles(str+@"\Input");
            for (int i = 0; i < ABs.Length; ++i)
            {
                string fileName = Path.GetFileNameWithoutExtension(ABs[i]);
                Byte[] temp = File.ReadAllBytes(str+@"\Input\"+fileName+".assetbundle");
                Encypt(ref temp);
                File.WriteAllBytes(str+@"\Output\"+fileName+"Encypted.assetbundle", temp);
            }
        }

        //加密函数,这里是一个很简单的例子。更简单的方法还有在最后一位增加一个字符使Disunity解析文件失败等。
        static void Encypt(ref Byte[] targetData)
        {
            int dataLength = targetData.Length;
            for (int i = 0; i < dataLength; ++i) 
            {
                //对targetData中的每一byte都和10011101做异或运算。
                targetData[i] = (byte)(targetData[i] ^ key);
            }
        }
    }
}

这样以后,在Output文件夹中就是加密过的AssetBundle。


我们可以用System.IO.File或者Unity的WWW类等将加密过的AssetBundle作为普通的二进制文件加载进内存,利用File.ReadAllBytes或者WWW.bytes读取其二进制形式。此时,在Unity中对该二进制数组进行加密函数的逆运算(示例代码是最简单的对称式加密,且加密函数就是解密函数)。


二进制文件而在AssetBundleAssetBundle类中有一个方法:AssetBundle.CreateFromMemory。这个方法可以将内存的一段二进制块转变为AssetBundle。对解密后的内存调用此函数后,原来的AssetBundle就回来咯~


另外提供一种比较丧病的思路(我并没有去试),即把所有的脚本、资源部分(C#也看成是脚本)都进行加壳,在mono的本地运行时劫持加载函数去脱壳……似乎好像可以对mono_image_load_file_for_image这样一个函数去动动手脚,或者直接拿Github上的mono去改一下,生成一个特制的运行时……?有路过的大神还望不吝赐教。


嘛,il2cpp以后mono运行时这种东西已经不重要了,应该是的吧?

你可能感兴趣的:(Unity开发)