rgss加密文件解包器_Unity AssetBundle高效加密案例分享
這是侑虎科技第585篇文章,感謝作者江魚供稿。歡迎轉(zhuǎn)發(fā)分享,未經(jīng)作者授權(quán)請勿轉(zhuǎn)載。如果您有任何獨到的見解或者發(fā)現(xiàn)也歡迎聯(lián)系我們,一起探討。(QQ群:793972859)
作者主頁:https://www.zhihu.com/people/yu-jiang-3-65/,作者也是U Sparkle活動參與者,UWA歡迎更多開發(fā)朋友加入U Sparkle開發(fā)者計劃,這個舞臺有你更精彩!
隨著AssetStudio的普及,Unity項目中使用的AssetBundle資源可以被各種小白用戶解包提取,由此AssetBundle資源包的安全問題不得不引起我們重視。
過去,通過官方文檔的了解,我們主要可以通過,AssetBundle.LoadFromMemory(Async)的方案來實現(xiàn)資源包加密,官方文檔對這個方法是這樣描述的:
Use this method to create an AssetBundle from an array of bytes. This is useful when you have downloaded the data with encryption and need to create the AssetBundle from the unencrypted bytes.Compared to LoadFromMemoryAsync, this version is synchronous and will not return until it is done creating the AssetBundle object.
下面是官方文檔中的示例代碼:
using UnityEngine; using UnityEngine.Networking; using System.Collections;public class ExampleClass : MonoBehaviour {byte[] MyDecription(byte[] binary){byte[] decrypted = new byte[1024];return decrypted;}IEnumerator Start(){var uwr = UnityWebRequest.Get("http://myserver/myBundle.unity3d");yield return uwr.SendWebRequest();byte[] decryptedBytes = MyDecription(uwr.downloadHandler.data);AssetBundle.LoadFromMemory(decryptedBytes);} }需要注意的是,對于AssetBundle.LoadFromMemory(Async)這個方法,在官方的AssetBundle foudamentals一文中,官方又非常明確的指出:
Unity's recommendation is not to use this API.AssetBundle.LoadFromMemoryAsync loads an AssetBundle from a managed-code byte array (byte[] in C#). It will always copy the source data from the managed-code byte array into a newly-allocated, contiguous block of native memory. If the AssetBundle is LZMA compressed, it will decompress the AssetBundle while copying. Uncompressed and LZ4-compressed AssetBundles will be copied verbatim.
The peak amount of memory consumed by this API will be at least twice the size of the AssetBundle: one copy in native memory created by the API, and one copy in the managed byte array passed to the API. Assets loaded from an AssetBundle created via this API will therefore be duplicated three times in memory: once in the managed-code byte array, once in the native-memory copy of the AssetBundle and a third time in GPU or system memory for the asset itself.
Prior to Unity 5.3.3, this API was known as AssetBundle.CreateFromMemory. Its functionality has not changed.
從官方的解釋中,我們可以看到AssetBundle.LoadFromMemory(Async)的使用成本非常高昂,不被推薦是自然而然的事情。但是,有沒有更高效便捷的方式去對AssetBundle進行加密處理,防止被小白用戶利用AssetStudio之類的工具輕易地提取到AssetBundle的資源呢?
在查看Unity API的時候發(fā)現(xiàn)LoadFromFile末尾有一個offset參數(shù),那么這個參數(shù)有什么用呢?是否可以起到防止AssetBundle資源直接被AssetStudio提取呢?先看官方文檔的接口說明:
public static AssetBundle LoadFromFile(string path, uint crc, along offset);ParametersReturnsAssetBundle Loaded AssetBundle object or null if failed.DescriptionSynchronously loads an AssetBundle from a file on disk.
The function supports bundles of any compression type. In case of lzma compression, the data will be decompressed to the memory. Uncompressed and chunk-compressed bundles can be read directly from disk.
Compared to LoadFromFileAsync, this version is synchronous and will not return until it is done creating the AssetBundle object.
This is the fastest way to load an AssetBundle.
官方文檔的代碼示例并沒有,提供offest參數(shù)的演示,所以在這里就不搬運了,接下來我會用自己寫的測試代碼來做演示。
首先,我們需將XAsset生成好的AssetBundle文件內(nèi)容進行偏移處理,待Unity打包完成后遍歷所有AssetBundle文件,并對文件添加offset后進行覆蓋,代碼如下:
foreach (string bundleName in bundleNames) {string filepath = outputPath + "/" + bundleName;// 利用 hashcode 做偏移 string hashcode = manifest.GetAssetBundleHash(bundleName).ToString();ulong offset = Utility.GetOffset(hashcode);if ( offset > 0){byte[] filedata = File.ReadAllBytes(filepath);int filelen = ((int)offset + filedata.Length);byte[] buffer = new byte[filelen];copyHead(filedata, buffer, (uint)offset);copyTo(filedata, buffer, (uint)offset);FileStream fs = File.OpenWrite(filepath);fs.Write(buffer, 0, filelen);fs.Close();offsets += filepath + " offset:" + offset + "n";}WriteItem(stream, bundleName, filepath, hashcode); }然后,我們再進行加載測試,我們分別使用offset參數(shù)加載AssetBundle,和模擬解密文件后從內(nèi)存中加載AssetBundle然后讀取其中的一個Texture用于顯示,可以參考以下代碼:
// 基于offset加載AssetBundle async void onLoadWithOffsetClicked() {if (offsetBundle)offsetBundle.Unload(true);var current_memory = Profiler.GetTotalAllocatedMemoryLong();display_image.texture = null;var path = System.IO.Path.Combine(Application.streamingAssetsPath, "assets_previews_offset");var assetBundleRequest = AssetBundle.LoadFromFileAsync(path, 0, 294);await assetBundleRequest;var texture = assetBundleRequest.assetBundle.LoadAsset<Texture2D>("download.jpg");display_image.texture = texture;offsetBundle = assetBundleRequest.assetBundle;Debug.Log("Offset Load Complete:" + (Profiler.GetTotalAllocatedMemoryLong() - current_memory)); }// 基于Menmory加載AssetBundle async void onLoadWithMemoryClicked() {if (memoryBundle)memoryBundle.Unload(true);var current_memory = Profiler.GetTotalAllocatedMemoryLong();display_image.texture = null;var path = System.IO.Path.Combine(Application.streamingAssetsPath, "assets_previews");WWW www = new WWW("file://" + path);await www;var request = AssetBundle.LoadFromMemoryAsync( www.bytes);await request;var texture = request.assetBundle.LoadAsset<Texture2D>("download.jpg");display_image.texture = texture;memoryBundle = request.assetBundle;www.Dispose();Debug.Log("Memory Load Complete:"+ (Profiler.GetTotalAllocatedMemoryLong() - current_memory)); }接下來,我們再看看對以上兩個函數(shù)執(zhí)行的Profiler數(shù)據(jù)分析采樣的結(jié)果:
測試場景截圖使用offset參數(shù)加載之前的內(nèi)存情況使用offset參數(shù)加載AssetBundle之后的內(nèi)存情況使用LoadFromMemory加載之前的內(nèi)存情況使用LoadFromMemory加載之后的內(nèi)存情況通過對比發(fā)現(xiàn),使用LoadFromMemory內(nèi)存明顯發(fā)生了增長,并且在加載過程中還出現(xiàn)了一個內(nèi)存高峰。
由于我們對AssetBundle的資源進行了偏移,勢必在理論上,AssetStudio無法直接解析出我們Unity工程中的AssetBundle,接下來我們再來看下,我們的理論是否經(jīng)得起實踐的考驗。
經(jīng)測試,沒加offset的時候可以輕易地用AssetStudio預覽AssetBundle中的資源,請參考下圖(因為用的是公司項目的資源所以需要打碼處理):
帶offset的資源,發(fā)現(xiàn)和我們的理論推測結(jié)果一致,請參考:
在測試過程中發(fā)現(xiàn),有些老版本的AssetStudio,在解析帶offest的資源的時候甚至會直接奔潰。其實,對于資源加密,我們大多數(shù)時候能做到的是防小白不防專家,不管你是采用簡單的或者復雜的,在反編譯高手手里都有點蒼白,我親眼所見一個大佬用IDA把人家的通信加密算法反出來了,所以這里就不做更深入的分析了。
文末,再次感謝江魚的分享,如果您有任何獨到的見解或者發(fā)現(xiàn)也歡迎聯(lián)系我們,一起探討。(QQ群:793972859)
也歡迎大家來積極參與U Sparkle開發(fā)者計劃,簡稱“US”,代表你和我,代表UWA和開發(fā)者在一起!
總結(jié)
以上是生活随笔為你收集整理的rgss加密文件解包器_Unity AssetBundle高效加密案例分享的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java-标识符和关键字
- 下一篇: express模板引擎 html,Exp