Unity3D DLL加密

Unity3D打包android应用程序时,如果不对DLL加密,很容易被反编译,导致代码的泄露。通常的做法是通过加密DLL或者对代码进行混淆。本文的所要探讨的是通过加密的方式来对DLL进行保护,并详细记录加密的操作过程。

主要参考

雨松的博文:http://www.xuanyusong.com/archives/3553

http://csftech.logdown.com/posts/452269-android-unity-encryption

这两篇文章已经详细介绍了加密的过程,但是还是有些坑和有些操作没有给出。

原理说明

所有的代码编译后是在apk\assets\bin\Data\Managed\Assembly-CSharp.dll下,要做的就是对这个DLL进行加密,Assembly-CSharp.dll由libmono.so加载,所以需要在libmono.so中对加密过的Assembly-CSharp.dll进行解密,幸好unity提供了mono的代码可以进行编译修改。当然对于libmono.so也存在被反编译的风险,本文暂不考虑。

准备

  • linux系统。本文选择采用的是Ubuntu14.04,虚拟机也可以,另外可以用Windows + Cygwin进行编译,不过考虑到这样做可能踩坑更多,果断放弃。
  • unity mono源码,可以在https://github.com/Unity-Technologies/mono下载,branch选择unity4.6,直接下zip包,或者git下来都可以,下载下来的zip包为mono-unity-4.6.zip。
  • unity3d 4.6版本,本文试验的是4.6的编译,注意一定要安装4.6.6+的版本,否则重编的libmono.so会报错(坑一)。
  • android ndk, 版本可以根据unity-mono中用的版本来下载,参见unity-mono/external/buildscripts/build_runtime_android.sh, 搜一下ndk=就能找到,本文用到的是r10e,下载下来的ndk为android-ndk-r10e-linux-x86_64.bin。
  • apktools, 用来对apk进行解包签名打包,2.0以上版本,否则打包是会报错。

编译mono

1)为了方便使用root进行编译,Ubuntu下root默认不开启,可以使用:

sudo passwd root

输两次密码后

su -

进行登录

2)NDK安装

安装7z

apt-get install p7zip-full

解压

7z x android-ndk-r10e-linux-x86.bin

配置环境变量,配置方法有很多,可以修改/etc/profile或者~/.bashrc,这里直接shell下添加临时的环境变量,不添加后面编mono时会报找不到NDK

export ANDROID_NDK_ROOT=/home/xubo/unity-dev/android-ndk-r10e

export PATH=$ANDROID_NDK_ROOT:$PATH

3)检查一下mono使用的NDK版本

vi打开mono-unity-4.6/external/buildscripts/build_runtime_android.sh可以找到

perl ${BUILDSCRIPTSDIR}/PrepareAndroidSDK.pl -ndk=r10e -env=envsetup.sh && source envsetup.sh

这里可以确定当前的unity mono使用r10e来进行编译的

4)安装编译必备的一些包

apt-get install autoconf automake bison build-essential gettext git libglib2.0 libtool perl

5)尝试第一次编译

./external/buildscripts/build_runtime_android.sh

报错:

/usr/bin/env: perl -w: No such file or directory

这里unity-mono编译的时候会去git 一个包android_krait_signal_handler,在external目录下,就是这个包报错,这个包出错的问题很多,是个巨坑(坑二)。

打开android_krait_signal_handler/build.pl,将第一行

#!/usr/bin/env perl -w

改为

#!/usr/bin/perl -w

将下面行

PrepareAndroidSDK::GetAndroidSDK(undef, undef, "r9");

改为实际用到的NDK

PrepareAndroidSDK::GetAndroidSDK(undef, undef, "r10e");

将buildscripts/PrepareAndroidSDK.pm替        换android_krait_signal_handler/PrepareAndroidSDK.pm

打开jni/Application.mk将下两行都删掉

APP_PLATFORM := android-9
NDK_TOOLCHAIN_VERSION := clang3.3

否则会报下面的错误

make: execvp: /home/xubo/unity-dev/android-ndk-r10e/toolchains/arm-linux-androideabi-4.8: Permission denied

6)尝试第二次编译

configure不通过,打开config.log发现

./configure: line 4546: /home/xubo/unity-dev/android-ndk-r10e/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc: No such file or directory

检查该目录,发现文件是存在的,这里是因为虽然NDK是64位的,但是交叉编译工具链是32位的,安装一下,而本文采用的编译机是64位的,安装一下64位下运行32位可执行文件的包

apt-get install lib32z1 lib32ncurses5 lib32bz2-1.0

7)尝试第三次编译,至此我们应该可以编译成功了,但还没涉及到加解密,注意编译需要在mono的根目录下进行。最终显示如下则OK:

Build SUCCESS!
Android STATIC/SHARED libraries are found here: builds/embedruntimes/android

加密程序

加密过程可参考上面的链接,就是将Assembly-CSharp.dll视作普通的文件,随便用什么语言写个加密的代码,简单的可以修改几个字节,做偏移啥的,生成一个新的Assembly-CSharp.dll,替换原来的,这样一般的破解软件就没辙了。

MONO解密

上面只是试验了一下mono的编译,关于将解密的代码添加至mono还没有做。

打开mono-unity-5.3/mono/metadata/image.c,找到mono_image_open_from_data_with_name函数修改如下

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(name != NULL)
        {
            if(strstr(name,"Assembly-CSharp.dll")){
                //这里写下你的解密的代码,入参data是从Assembly-CSharp.dll读文件读出来的
                //被加密的原始数据,通过你的解密代码生成一段新的data
            }
        }
        
        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);
        }

MONO正式编译

正式编译mono前,还有两个地方要修改,不修改编译出来的是debug版本,libmono.so有8M,

打开build_runtime_android.sh, 将下面标红的-g给去掉,编译release版本

CFLAGS="-DANDROID -DPLATFORM_ANDROID -DLINUX -D__linux__ -DHAVE_USR_INCLUDE_MALLOC_H -DPAGE_SIZE=0x1000 -D_POSIX_PATH_MAX=256 -DS_IWRITE=S_IWUSR -DHAVE_PTHREAD_MUTEX_TIMEDLOCK -fpic -g -funwind-tables \

同样build_runtime_android_x86.sh里面也去掉

Unity3D 签名

别忘记了,需要unity4.6.6+的版本,本文是在unity4.6.9下测试OK。

制作一个签名,后面在用apktool重新封包时用得到,用这个签名对游戏进行build。

Apktool解包封包

1)(windows下操作)确定apktool目录下有aapt.exe,apktool.bat,apktool.jar,确定版本是2.0+

2)将生成的包例如1.apk 复制到apktool/下

3)cmd命令行下,进入apktool目录,执行apktool d 1.apk进行解包,会在apktool下生成与包名相同的文件夹1/

4) 将加密过的Assembly-CSharp.dll覆盖1\assets\bin\Data\Managed\Assembly-CSharp.dll

5) 将编译过的libmono.so,注意这里选择armv7a/,和x86/下的,分别覆盖1\lib\armeabi-v7a和1\lib\x86\下的libmono.so

6) 封包命令行下执行apktool b -f 1,会在1/下生成dist文件,里头就是新封的包,改名为2.apk,并复制到apktool/下

7)签名,隐去的是你要填的签名文件名,和别名

jarsigner -verbose -keystore ****.keystore -signedjar 2_s.apk 2.apk ****

8)2_s.apk就是你加密过的包,进行安装测试

libmono.so加密

雨松还提到了libmono.so的加密,这里先不涉及吧,strip动态库,可能能起到相同的效果。

小结

这样加密经过测试是OK的,可以防止一般的反编译软件进行破解了,对于高手可能还防不住,另外编译mono有点心惊胆战,android_krait_signal_handler这个工程是个坑,还是有点担心编出来的libmono.so有咩有啥隐患,所以这样弄需要在各种android机子上多测试。

时间: 2024-08-25 19:04:11

Unity3D DLL加密的相关文章

一次U3D DLL加密的记录(二)

上一篇文章一次U3D DLL加密的记录(一)已经介绍了Assembly-CSharp.dll的加密和打包方法,但每次都得导出安卓工程,接着替换资源,再导出apk,这样以来是非常繁琐的. 这篇文章主要针对windows下对u3d游戏的加密一键打包的介绍 主要步骤: ①:编译加密后的libmono.so ②:在自定义方法中对Assembly-CSharp.dll进行加密 ③:破解UnityEditor.Android.Extensions.dll,注入自定义方法 ④:一键打包 首先参考一下我的<一次

一次U3D DLL加密的记录(一)

这篇文章主要针对windows下对u3d游戏的加密过程 主要步骤: ①:编译和替换加密后的libmono.so ②:导出安卓工程 ③:加密和替换Assembly-CSharp.dll ④:用eclipse等工具导出apk 首先参考一下我的<一次编译libmono.so的记录> 接着把项目导出成安卓工程,在xxx/assets/bin/Data/Managed下找到Assembly-CSharp.dll,然后写个文件读写程序进行破坏c#程序集结构,从而达到该程序集解不开的目的 示例程序代码如下:

Unity3D内容加密保护

仅管资源 (Assets) 在传输时可使用加密进行保护,但在数据流入客户手中后.其内容就有可能被获取.比如,有工具可记录驱动程序级别上的 3D 数据,同意用户提取传送至 GPU 的模型和纹理. 因此,我们通常希望在用户决定提取资源时.可以满足其要求. 当然,假设您须要.也能够对资源包 (AssetBundle) 文件使用自己的数据加密. 一种方法是,使用文本资源 (AssetBundle) 类型将数据存储为字节.您能够加密数据文件,并使用扩展名 .bytes 进行保存,Unity 会将其视为文本

unity3d中加密保存本地存档

unity中提供了PlayerPrefs来存储和读取本地的存档,根据unity的文档显示,很容易就能找到这些信息存储的位置 而且是明文的,很容易就看懂了 也可以修改,如何避免这种情况了,不如就加密一下吧,打字太累 直接上代码,需要的朋友拿走吧,当然加密的Key自己设定好了 using System; using System.IO; using System.Security.Cryptography; using System.Text; using UnityEngine; public c

.Net,Dll扫盲篇,如何在VS中调试已经编译好的dll?

什么是Dll? DLL 是一个包含可由多个程序同时使用的代码和数据的库. 例如,在 Windows 操作系统中,Comdlg32 DLL 执行与对话框有关的常见函数.因此,每个程序都可以使用该Dll中包含的功能来实现"打开"对话框.这有助于促进代码重用和内存的有效使用.通过使用 DLL,程序可以实现模块化,由相对独立的组件组成.通俗来讲,一个项目由多个模块组成.可以在运行时将各个模块加载到主程序中(如果安装了相应模块).因为模块是彼此独立的,所以程序的加载速度更快,而且模块只在相应的功

Java调用dll的实现

Java工程实现调用dll加密: 一.idea中 生成一个Java文件,加载库dll,声明native函数: static { System.loadLibrary("Test_SimpleEncryForJava"); } public native static void SimpleEncryFile(String srcFile, String desFile, String passwd); 通过命令行进入合适的目录,javah + 类名生成.h文件(不需要.java后缀).

【SQLite的简单使用】

[SQLite管理工具简介] 推荐以下2款: Navicat for SQLite:功能非常强大,几乎包含了数据库管理工具的所有必需功能,操作简单,容易上手.唯一的缺点是不能打开由System.Data.SQLite.dll加密过的数据库. Database.Net:台湾人用.net开发的全能数据库管理工具,可以管理多种数据库,包括MSSQL.MYSQL.IBM DB2.Oracle.Access.Excel.OleDb.Odbc等十多种数据库(或数据接口),功能没有Navicat那么多,只包含

.NET中的PublicKeyToken以及强命名问题

在.NET的GAC出现之前,曾经有DLL Hell的问题.这是因为当时对于共享的DLL的处理方式,是通过采用注册表的方式实现的.当我们安装一个程序A的时候,这个程序包含一个共享的DLL,那么这个DLL就会就会写入到注册表中,但是注意这里并没有写入版本信息,只是告诉你在哪个地方有一个叫做XX的DLL可以使用.当安装另外的一个程序B的时候,也包含这个共享的DLL,但是是一个更加新一些的版本,系统会发现这个DLL已经注册存在了,就会用这个DLL去覆盖原来的DLL,但是因为注册表中前后没有任何版本的标示

激活码方式注册的实现原理述

加密混淆授权 1. 软件授权方式概述 目前,商用软件和共享软件绝大部份都是采用注册码授权的方式来保证软件本身不被盗用,以保证自身的利益.尽管很多常用的许多软件系统的某些版本已经被别人破解,但对于软件特殊行业而言,注册码授权的方式还是一种保护软件系统本身的一种有效的手段. 通常而言,注册码授权方式有以下几种方式: l 安装序列号方式 这是最为常用的方式,Microsoft提供的产品(例如:Windows系列产品.Office系列产品等等)都是采用这种方式.通过一种复杂的算法生成安装序列号,在安装过