Unity Dll 加密

引子

给Unity Dll 加密

软件环境

  • VirturlBox 虚拟机 5.10
  • 虚拟机 Centos 7 64bit 系统
  • Untiy 2017 版本

原理

Unity 编译代码会生成以下几个文件:

  1. Plugins 代码编译为 Assembly-CSharp-firstpass.dll
  2. Editor 代码会编译为 Assembly-CSharp-Editor.dll
  3. Plugins-Editor 代码会编译为 Assembly-CSharp-Editor-firstpass.dll
  4. 其他代码会编译为 Assembly-CSharp.dll

可以选择加密 Assembly-CSharp.dll 文件

加密完文件,要保证Unity能识别加载,需要二进制还原

Unity 使用libmono.so 加载DLL文件

Unity mono 源码

函数在 image.c 文件内,修改其中的 mono_image_open_from_data_with_name 方法

修改前

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
MonoImage *
mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)
{
MonoCLIImageInfo *iinfo;
MonoImage *image;
char *datac;

if (!data || !data_len) {
if (status)
*status = MONO_IMAGE_IMAGE_INVALID;
return NULL;
}
datac = data;
if (need_copy) {
datac = g_try_malloc (data_len);
if (!datac) {
if (status)
*status = MONO_IMAGE_ERROR_ERRNO;
return NULL;
}
memcpy (datac, data, data_len);
}

image = g_new0 (MonoImage, 1);
image->raw_data = datac;
image->raw_data_len = data_len;
image->raw_data_allocated = need_copy;
image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
iinfo = g_new0 (MonoCLIImageInfo, 1);
image->image_info = iinfo;
image->ref_only = refonly;
image->ref_count = 1;

image = do_mono_image_load (image, status, TRUE, TRUE);
if (image == NULL)
return NULL;

return register_image (image);
}

修改后

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
MonoImage *
mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)
{
//修改数据流开始 内部的实现方法,可以自己定
if(strstr(name,"Assembly-CSharp.dll")){
int xorkey = 201;
int i = 0;
for (i = 3; i < 11; ++i)
{
data[i] = (data[i]^xorkey);
}
}
//修改数据流结束

MonoCLIImageInfo *iinfo;
MonoImage *image;
char *datac;

if (!data || !data_len) {
if (status)
*status = MONO_IMAGE_IMAGE_INVALID;
return NULL;
}
datac = data;
if (need_copy) {
datac = g_try_malloc (data_len);
if (!datac) {
if (status)
*status = MONO_IMAGE_ERROR_ERRNO;
return NULL;
}
memcpy (datac, data, data_len);
}

image = g_new0 (MonoImage, 1);
image->raw_data = datac;
image->raw_data_len = data_len;
image->raw_data_allocated = need_copy;
image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
iinfo = g_new0 (MonoCLIImageInfo, 1);
image->image_info = iinfo;
image->ref_only = refonly;
image->ref_count = 1;

image = do_mono_image_load (image, status, TRUE, TRUE);
if (image == NULL)
return NULL;

return register_image (image);
}

过程

安装 CentOS 7

更换镜像源

参考其他文章

Vbox文件共享

参考其他文章

为了方便 文件传输

Mono代码下载

1
git clone https://github.com/Unity-Technologies/mono.git mono

编译代码

编译哪个版本的mono 需要切换到对应的分支上

1
git checkout -b unity-2017.1

需要安装 pkg-config, glib 2.4

1
yum install pkgconfig glib2

当获取到源码以后是这样一个界面

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
[root@localhost mono-unity-2017.1]# tree -L 1
.
├── acinclude.m4
├── add_to_build_results
├── AUTHORS
├── autogen.sh
├── ChangeLog
├── CMakeLists.txt
├── configure.in
├── config.xarm-windows.h
├── COPYING.LIB
├── data
├── docs
├── eglib
├── envsetup.sh
├── external
├── ikvm-native
├── libgc
├── LICENSE
├── Makefile.am
├── man
├── mcs
├── mkinstalldirs
├── mono
├── mono-core.spec.in
├── mono-uninstalled.pc.in
├── mono-win32-setup-light.bmp
├── monowiz.win32.nsi
├── msvc
├── NEWS
├── nls.m4
├── notes
├── perl_lib
├── po
├── po.m4
├── progtest.m4
├── README
├── README.vsnet
├── runtime
├── samples
├── scripts
├── support
├── tools
└── tuning

20 directories, 22 files

在当前目录下执行脚本

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
# sh external/buildscripts/build_runtime_android.sh
Environment:
Host = linux
Temporary = /tmp
Home = /root


Installing NDK 'r10e':
$ANDROID_NDK_ROOT not set; using /root/android-ndk_auto-r10e instead
Downloading 'r10e' to '/root/android-ndk_auto-r10e'
URL: http://dl.google.com/android/ndk/android-ndk-r10e-linux-x86.bin
Output: /root/android-ndk_auto-r10e
Base: android-ndk-r10e-linux-x86
URL base: http://dl.google.com/android/ndk/
Suffix: .bin
Tmp DL: /tmp/android-ndk-r10e-linux-x86.bin
Tmp unpack: /tmp/android-ndk-r10e-linux-x86_unpack
Dest path: /root/
Dest name: android-ndk_auto-r10e
Can't exec "lwp-download": No such file or directory at /root/mono/mono-unity-2017.1/external/buildscripts/PrepareAndroidSDK.pm line 385.
Can't exec "/tmp/android-ndk-r10e-linux-x86.bin": No such file or directory at /root/mono/mono-unity-2017.1/external/buildscripts/PrepareAndroidSDK.pm line 403.

Outputing updated environment:
'envsetup.sh'

$ANDROID_NDK_ROOT = /root/android-ndk_auto-r10e

external/buildscripts/build_runtime_android.sh: line 14: source: envsetup.sh: file not found

去下载NDK,再配置

需要在envsetup.sh中设置ANDROID_NDK_ROOT的值

  1. 安装后发现缺少 libtool bison
1
yum install libtool bison
  1. 出现缺少g++
1
configure: error: You need to install g++

解决 安装g++工具

1
yum groupinstall "Development Tools"
  1. 缺少glib2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Package glib-2.0 was not found in the pkg-config search path.
Perhaps you should add the directory containing `glib-2.0.pc'
to the PKG_CONFIG_PATH environment variable
No package 'glib-2.0' found
Package gthread-2.0 was not found in the pkg-config search path.
Perhaps you should add the directory containing `gthread-2.0.pc'
to the PKG_CONFIG_PATH environment variable
No package 'gthread-2.0' found
Package glib-2.0 was not found in the pkg-config search path.
Perhaps you should add the directory containing `glib-2.0.pc'
to the PKG_CONFIG_PATH environment variable
No package 'glib-2.0' found
Package gthread-2.0 was not found in the pkg-config search path.
Perhaps you should add the directory containing `gthread-2.0.pc'
to the PKG_CONFIG_PATH environment variable
No package 'gthread-2.0' found
configure: error: You need at least glib-2.0 2.4.0

解决办法

1
yum install glib2-devel
  1. 再次编译 还是不通过,找到需要安装cmake
1
yum install cmake
  1. 到这里已经可以编译 Unity-5.3 版本的libmono.so
    但是之后的还是不能编译通过

  2. 解决Unity-2017 编译不能通过问题

问题如下:

1
It should have been installed in the `/usr/local/lib/mono/4.5/mscorlib.dll' directory.

解决办法:
需要安装Mono
验证 mono版本

1
mono -V

1
2
3
4
5
6
../../unity/unity_utils.h:32:34: error: unknown type name ‘vprintf_func’
void mono_unity_set_vprintf_func(vprintf_func func);
../../unity/unity_utils.h:34:42: error: unknown type name ‘MonoMemoryCallbacks’
void unity_mono_install_memory_callbacks(MonoMemoryCallbacks* callbacks);
../../unity/unity_utils.c:129:35: error: unknown type name ‘vprintf_func’
void mono_unity_set_vprintf_func (vprintf_func func)

最后还是失败了!!!

换成 Ubuntu 系统编译成功了

执行

1
./external/buildscripts/build_runtime_android.sh

编译成功以后

修改 image.c 代码

重编译

android_krait_signal_handler 项目 报错

1
./build.pl

安装perl lwp模块 下载最新的Android NDK资源

1
sudo yum install perl-libwww-perl

重新执行

执行

1
./external/buildscripts/build_runtime_android.sh

可以顺便修改下 mono_image_open_from_data 函数名

.h .c 两个地方都要改

1
2
3
4
5
6
7
8
```

### 修改 build_runtime_android 编译选项

编译时 不需要编译 ARMv5,ARMv6 两个版本
```
#clean_build "$CCFLAGS_ARMv5_CPU" "$LDFLAGS_ARMv5" "$OUTDIR/armv5"
#clean_build "$CCFLAGS_ARMv6_CPU" "$LDFLAGS_ARMv5" "$OUTDIR/armv6_vfp"

build_runtime_android.sh

arm 下
把CFLAGS里的-g改成-O2

build_runtime_android_x86.sh
x86 下
把CFLAGS里的-g 去掉