Unity AssetBundle efficient encryption Case Studies

https://blog.csdn.net/UWA4D/article/details/97903612

 

 

 

This is Yoo Tiger Technology 585 articles, thank the author river fish feeds. Welcome forwarded to share, please do not reprint without the author's authorization. If you have any insights or findings also welcome to contact us to explore together. (QQ group: 793 972 859)

On the home page: https: //www.zhihu.com/people/yu-jiang-3-65/, author of U Sparkle event participants, UWA welcome more friends to join the development of U Sparkle developer program, this stage you have more wonderful!

With the popularity of AssetStudio, AssetBundle Unity resources used in the project can be all kinds of white users unpack extraction, thus security AssetBundle resource pack have brought to our attention.

In the past, through the official document, we mainly through, AssetBundle.LoadFromMemory (Async) programs to achieve resource packet encryption, the official documentation of this method is described:

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.

Here is sample code official document:

UnityEngine the using;
the using UnityEngine.Networking;
the using the System.Collections;

public class the ExampleClass: MonoBehaviour
{
byte [] MyDecription (byte [] binary)
{
byte [] = DECRYPTED new new byte [1024];
return DECRYPTED;
}

the IEnumerator the Start ()
{
UnityWebRequest.Get UWR = var ( "HTTP: //myserver/myBundle.unity3d");
the yield uwr.SendWebRequest return ();
byte [] = decryptedBytes MyDecription (uwr.downloadHandler.data);
AssetBundle.LoadFromMemory (decryptedBytes);
}
}
Note that, for AssetBundle.LoadFromMemory (Async) this method, in the official AssetBundle foudamentals article, official and very clearly states:

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.

From the official explanation, we can see AssetBundle.LoadFromMemory (Async) using very costly, not to be recommended is a natural thing. However, there is no more efficient and convenient way to encrypt to AssetBundle, to prevent white users to easily extract resources AssetBundle it using the tools AssetStudio like?

View Unity API in the end it was found to have a LoadFromFile offset parameters, then the parameters of what use is it? It can serve to prevent AssetBundle resources directly AssetStudio extract it? Look at the Interface Description official document:

public static AssetBundle LoadFromFile(string path, uint crc, along offset);

Parameters

 

Returns
AssetBundle Loaded AssetBundle object or null if failed.

Description
Synchronously 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.

The sample code official document did not provide demo offest parameter, so here not carry, and then I would use to write their own test code to do the demonstration.

First, we need to generate a good AssetBundle XAsset offset processing contents of the file to be packaged Unity AssetBundle After completion through all files, add files and covered offset, as follows:

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);
}
We then loaded the test, we were AssetBundle offset parameter is used to load, decrypt, and simulation files loaded from memory and then read AssetBundle therein for displaying a Texture can reference the following code:

// 基于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 ( "the Load Complete Memory:" + (Profiler.GetTotalAllocatedMemoryLong () - current_memory));
}
Next, we look at the results of performing Profiler data analysis functions of the above two samples:


Screenshot test scenarios
 


Use the offset parameter memory conditions before loading
 


Use offset parameter memory situation after loading AssetBundle
 


Use memory load situation before LoadFromMemory
 


Use memory situation after LoadFromMemory load
 

 

 

By comparison, the use of LoadFromMemory memory significantly increase took place, and during the loading process also appeared a peak memory.

Since we had to shift resources AssetBundle is bound in theory, AssetStudio we can not be resolved directly Unity project AssetBundle, then we look at, if our theory stand the test of practice.

After testing, did not increase offset when you can easily use AssetStudio preview AssetBundle resources, please refer to the diagram (because of resource companies with projects it is necessary to deal with a code):

 

 

Results are consistent with offset resource discovery and our theoretical speculation, please refer to:

 

Guess you like

Origin www.cnblogs.com/nafio/p/11811251.html