Unity3D实战之文件加密

移动端游戏经常被一些玩家破解成白包,但是为了安全性,开发者还是需要使用算法对文本文件加密,加密的算法非常多,比如通常使用的是MD5算法,OBFS算法,SHA512算法等。由于MD5算法经常使用,网上也有现成的代码本节就直接掠过,直接讲OBFS,SHA512加密算法,为了便于大家理解,先把加密算法代码奉献上,加密函数代码如下所示:

//OBFS加密算法
    private static string OBFS(string str)
    {
        int length = str.Length;
        var array = new char[length];
        for (int i = 0; i < array.Length; i++)
        {
            char c = str[i];
            var b = (byte)(c ^ length - i);
            var b2 = (byte)((c >> 8) ^ i);
            array[i] = (char)(b2 << 8 | b);
        }
        return new string(array);
    }

    //SHA512加密算法
    public static string GetSHA512Password(string password)  
    {  
        byte[] bytes = Encoding.UTF7.GetBytes(password);  
        byte[] result;  
        SHA512 shaM = new SHA512Managed();  
        result = shaM.ComputeHash(bytes);  
        StringBuilder sb = new StringBuilder();  
        foreach (byte num in result)  
        {  
            sb.AppendFormat("{0:x2}", num);  
        }  
        return sb.ToString();  
    }

以上两个算法实现了文本文件的密码,函数的参数是开发者自己定义的字符串,然后在该字符串的基础上通过算法加密生成新的字符串用于压缩文件加密。下面列出配置文件,并且调用OBFS函数或者是SHA512函数对文件进行加密,返回的是经过加密字符串,同时调用函数SaveConfigXMLTOZip对文件进行压缩加密。对应的函数语句如下所示:

private const string configurationFile = "config.txt";
    private const string localizationFile = "translations.txt";
    private /*const*/ string configurationZipPwd = OBFS("~Ũɦ;о_ٷݫ࠵ळੰୠ_");
private /*const*/ string configurationZipPwd = GetSHA512Password("ٷ※▊ぷ┩▓ㄘЖ╔╕Ψ≮≯ゆǘйξζ");
#if UNITY_EDITOR
    protected void SaveConfigXMLToZip()
    {
        using (ZipFile zipFile = new ZipFile(Encoding.UTF8))
        {
            zipFile.Password = configurationZipPwd;
            zipFile.AddEntry(configurationFile, configuration.bytes);
            zipFile.AddEntry(localizationFile, localization.bytes);
            string zipPath = Path.Combine(Application.persistentDataPath, configurationZipFile);
            LogTool.Log("Saving configuration in \"" + zipPath + "\"");
            zipFile.Save(zipPath);
        }
    }
#endif

文件的压缩是在编辑模式下,程序运行时会将文本文件压缩同时把加密的密码赋值给它,在程序启动时,先从资源服务器加载文件的版本号,通过与本地的版本号对比决定下载需要的文本文件。函数代码如下所示:

#region Coroutines
    IEnumerator DownloadVersionFile()
    {
        Asserts.Assert(!downloadingVersionFile);
        downloadingVersionFile = true;

        WWW versionLoader = new WWW(configurationZipURL + versionFile + "?nocache=" + Environment.TickCount);

        while (!versionLoader.isDone)
        {
            yield return new WaitForEndOfFrame();
        }

        if (versionLoader.isDone && string.IsNullOrEmpty(versionLoader.error))
        {
            versionString = versionLoader.text;
        }
        else
            versionString = version.text;

        versionLoader.Dispose();

        LogTool.Log("VERSION NUMBER: " + versionString);

            downloadingVersionFile = false;

        PlayerPrefs.SetInt("last_vn", lastVersionNumber);
    }

它的下载方式是通过WWW下载的,先从资源服务器下载版本的文本文件,接下来下载文件的压缩包,函数代码如下所示:

 IEnumerator DownloadZip()
    {
        Asserts.Assert(!downloadingZip);
        downloadingZip = true;
        WWW zipLoader = new WWW(configurationZipURL + configurationZipFile + "?nocache=" + Environment.TickCount);

        while (!zipLoader.isDone)
        {
            if (stopDownloading)
            {
                downloadingZip = false;
                stopDownloading = false;

                LogTool.Log("Download configuration STOPPED!");
            }

            yield return new WaitForEndOfFrame();
        }

        if (zipLoader.isDone && string.IsNullOrEmpty(zipLoader.error))
        {
            LogTool.Log("**** PELLE: DOWNLOADING ZIP COMPLETED! Duration: " + (Time.realtimeSinceStartup - startTime));
            using (FileStream fs = new FileStream(Path.Combine(Application.persistentDataPath, configurationZipFile), FileMode.Create))
            {
                fs.Seek(0, SeekOrigin.Begin);
                fs.Write(zipLoader.bytes, 0, zipLoader.bytes.Length);
                fs.Flush();
            }

            zipLoader.Dispose();

            if (!downloadingZip)
            {
                LogTool.Log("Download configuration OK!");
                yield break;
            }
            else
                LogTool.Log("Download configuration OK, configurations will be loaded from new zip!");
        }
        else
        {
            zipLoader.Dispose();
            downloadingZip = false;
            stopDownloading = false;

            yield break;
        }

        if (!dataLoaded && !stopDownloading)
            this.TryLoadingXMLsFromZip();

        downloadingZip = false;
        stopDownloading = false;
    }

最后一步就是解压缩文件并且解释文本文件,函数代码如下所示:

  protected void TryLoadingXMLsFromZip()
    {
        string zipPath = Path.Combine(Application.persistentDataPath, configurationZipFile);
        if (!File.Exists(zipPath))
        {
            LogTool.Log("Configuration not found!");
            this.ParseConfigXML(configuration.text, false);
            this.ParseLocalizationXML(localization.text, false);
            return;
        }

        using (ZipFile zipFile = new ZipFile(zipPath, Encoding.UTF8))
        {
            zipFile.Password = configurationZipPwd;

            ZipEntry xmlConfEntry   = zipFile[configurationFile],
                     xmlLocaleEntry = zipFile[localizationFile];
            if (null == xmlConfEntry || null == xmlLocaleEntry)
            {
                LogTool.Log("Downloaded configuration INVALID!");
                this.ParseConfigXML(configuration.text, false);
                this.ParseLocalizationXML(localization.text, false);
                return;
            }

            using (MemoryStream ms = new MemoryStream())
            {
                xmlConfEntry.Extract(ms);

                string xmlText = Encoding.UTF8.GetString(ms.GetBuffer(), 0, ms.GetBuffer().Length);
                this.ParseConfigXML(xmlText, true);

                ms.Seek(0, SeekOrigin.Begin);
                xmlLocaleEntry.Extract(ms);

                xmlText = Encoding.UTF8.GetString(ms.GetBuffer(), 0, ms.GetBuffer().Length);
                this.ParseLocalizationXML(xmlText, true);
            }
        }
    }

这样整个加密流程就给读者介绍完了,后面将脚本挂接到对象上,在程序运行时做初始化操作处理就可以了,详情可以查看笔者已出版的著作:《Unity3D实战核心技术详解》一书。

笔者简介:姜雪伟个人网页

淘宝花钱买的最新版!需要的拿去! This asset obfuscates your code to make it harder for bad guys to reverse engineer your projects. Specifically designed for Unity, it seamlessly links in with its build process. The top priority of this package is to work straight out of the box with no extra steps required. While other obfuscators can stop a game from working, Beebyte's obfuscator looks for specific Unity related code that must be protected. The contents of your source files are unchanged, the obfuscation targets the compiled assembly. Features: - Supports IL2CPP - Supports Assembly Definition Files (Unity 2017.3+) - Removes Namespaces without any conflicts - Recognises Unity related code that must not be changed - Renames Classes (including MonoBehaviours) - Renames Methods - Renames Parameters - Renames Fields - Renames Properties - Renames Events - String literal obfuscation - Adds fake methods - Easy and extensive customisation using the Unity inspector window - Consistent name translations are possible across multiple builds and developers - Semantically secure cryptographic naming convention for renamed members The asset works for both Unity Free and Unity Pro version 4.2.0 onwards (including Unity 5 & 2017 & 2018). Build targets include Standalone, Android, iOS, WebGL, UWP. Other platforms are not guaranteed or supported but may become supported at a future date. IL2CPP builds are much harder to reverse engineer but strings and member information (class, method names etc) are visible in the global-metadata.dat file. Obfuscation will apply to this file adding further security. Why not complement your security with the Anti-Cheat Toolkit - a great third party asset. For more information about the Obfuscator, please see the FAQ
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海洋_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值