0%

UnityAB资源加密

1 最近学习了下 AB资源加密下面出来记录下
随着Unity的普及,现在已经越来越多的项目使用AB包,但是大部分都是没有加密的。比如某IP侵权的app,可以通过或者Unity内置的AssetBundleBrower直接看到ab包的所有资源
更甚者可以通过AssetStudio直接看到ab包的所有资源,图片,音频,动画,文本,CG视频等等(蒙皮动画目前不行),并且导出。
如果会写点代码,还可以在unity中,直接实例化出来,然后另存为Prefab,这样虽然无法获得fbx(其实fbx开源,自己反推写入数据也可以导出fbx),但是我们可以获得完整的Prefab,
设置内含了蒙皮信息。这样可以轻松获得所有的数据,贴图,音频,视频,模型,材质,蒙皮,动画等等

2 看了下AB资源的加密方式大概有几种
2.1 unity中国区提供的一种加密方式
2.2 对AB包的二进制文件进行加密操作
2.3 使用offest加密
还要其他的吧 暂时没了解

3 我看来看下对AB包的二进制文件进行加密操作

3.1 加密就是用秘钥跟ab文件异或处理,解密的时候也是再做一次异或处理即可,只要不被别人拿到秘钥就问题不大。
1
2
3
4
5
6
7
8
9
10
public static void Encypt(ref byte[] targetData, byte m_key)
{
//加密,与key异或,解密的时候同样如此
int dataLength = targetData.Length;
for (int i = 0; i < dataLength; ++i)
{
targetData[i] = (byte)(targetData[i] ^ m_key);
}
}

3.2 用算法加密
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
    [MenuItem("AssetBundle/AssetBundle_Window")]
public static void BuildAssetToWindow()
{
string outPath = Application.dataPath + "/../BuildAssetBundle/Window/";
CreateDir(outPath);
BuildPipeline.BuildAssetBundles(outPath,BuildAssetBundleOptions.ForceRebuildAssetBundle, BuildTarget.StandaloneWindows);
AssetDatabase.Refresh();
}
public static void CreateDir(string path)
{
DirectoryInfo info = new DirectoryInfo(path);
if (!info.Exists)
{
info.Create();
}
}

private IEnumerator EncryptionAB()
{
WWW www = new WWW("file:///D:\\fcj\\unity209\\VuforiaStudy\\BuildAssetBundle\\Window\\testab");
yield return www;
if (www.isDone)
{
if (www.error == null)
{
byte[] bytes = www.bytes;
for (int i = 0; i < bytes.Length; i++)//恺撒加密
{
bytes[i] += 1;
}
File.WriteAllBytes("D:\\fcj\\unity2018\\VuforiaStudy\\BuildAssetBundle\\Window\\myab_Encryption.assetbundle", bytes);
}
}
}

private IEnumerator DecryptAB()
{
WWW www = new WWW("file:///D:\\fcj\\unity2018\\VuforiaStudy\\BuildAssetBundle\\Window\\myab_Encryption.assetbundle");
yield return www;
if (www.isDone)
{
if (www.error == null)
{
byte[] bytes = www.bytes;
for (int i = 0; i < bytes.Length; i++)//恺撒解密
{
bytes[i] -= 1;
}
AssetBundle ab = AssetBundle.LoadFromMemory(bytes);
GameObject go = ab.LoadAsset("Sphere") as GameObject;//注意这里是预制体名字
Instantiate(go, Vector3.zero, Quaternion.identity);
ab.Unload(false);
}
}
}

```
3.3 自定义加密
比如他自己随机改数据里面的值 或者加上数据标头等等

```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;

/// <summary>
/// ab资源字节加密
/// </summary>
public class AssetBundleEncrypt {

private readonly static byte[] AssetHead = new byte[]
{
0x55, 0x6E, 0x69, 0x74,
0x78, 0x00, 0x32, 0x30,
};

private readonly static byte[] RiverHead = new byte[]
{
0x74, 0x69, 0x61,
};

private static Dictionary<byte, bool> helpDic = new Dictionary<byte, bool>();

// 加密
public static byte[] EncryptAsset(byte[] bytes, bool needNewByts = false)
{
var result = bytes;
if (needNewByts)
{
result = new MemoryStream(bytes).ToArray();
}
if (result.Length < 2048)
{ // 小于2048直接不加密
return result;
}
helpDic.Clear();
int mid = (AssetHead.Length - RiverHead.Length) / 2;
byte[] encryptBytes = new byte[mid * 2];

for (int i = 0, length = AssetHead.Length - RiverHead.Length; i < length; i+=2)
{
byte pos = 0;
byte value = 0;
pos = (byte)(Random.value * 255);
while (helpDic.ContainsKey(pos))
{
pos = (byte)(Random.value * 255);
}
helpDic.Add(pos, true);
if (i < mid)
{
value = result[pos + AssetHead.Length];
result[pos + AssetHead.Length] = (byte)(Random.value * 255);
}
else
{
value = result[result.Length - pos - 1];
result[result.Length - pos - 1] = (byte)(Random.value * 255);
}
encryptBytes[i] = pos;
encryptBytes[i + 1] = value;
}

for (int i = 0, length = RiverHead.Length; i < length; i++)
{
result[i] = RiverHead[i];
}
for (int i = RiverHead.Length, length = RiverHead.Length + encryptBytes.Length; i < length; i++)
{
result[i] = encryptBytes[i - RiverHead.Length];
}
return result;
}


// 解密
public static byte[] UnEncryptAsset(byte[] bytes, bool needNewByts = false)
{
var result = bytes;
if (needNewByts)
{
result = new MemoryStream(bytes).ToArray();
}
if(result.Length < 2048)
{ // 小于2048直接不加密
return result;
}

int mid = (AssetHead.Length - RiverHead.Length) / 2;
for (int i = 0, length = AssetHead.Length - RiverHead.Length; i < length; i+= 2)
{
byte pos = result[RiverHead.Length + i];
byte value = result[RiverHead.Length + i + 1];
if (i < mid)
{
result[pos + AssetHead.Length] = value;
}
else
{
result[result.Length - pos - 1] = value;
}
}
for (int i = 0, length = AssetHead.Length; i < length; i++)
{
result[i] = AssetHead[i];
}
return result;
}
}


//加密调用
string publishTempPath = GetFullUrlPublish(Path.GetFileName(resPath));
var bytes = File.ReadAllBytes(resPath);
if (type.ToLower() == ".unity3d")
bytes = AssetBundleEncrypt.EncryptAsset(bytes);
File.WriteAllBytes(publishTempPath, bytes);

//解密调用
var bytes = www.downloadHandler.data;
if (GameVersion.isHotUpdate || GameVersion.isSplitAsset)
bytes = AssetBundleEncrypt.UnEncryptAsset(bytes);
AssetBundle bundle = AssetBundle.LoadFromMemory(bytes);