Unity 3D Android对dll加密和重编译mono源码进行解密
为防止Unity 3D的dll代码被反编译,可对其进行加密,然后在libmono.so中添加解密代码,对mono源码重新编译打包出libmono.so替换项目中的so之后,项目便可正常运行。
但实际操作过程中,mono源码编译十分容易出错(步步掉坑啊 T_T~~~),几经周转,终于在CentOS6.6(32位)系统下搞定了。记录详细步骤如下:
1、对dll加密:
(1)先将Unity中项目代码导出为Android工程,找到要加密的dll,位于\assets\bin\Data\Managed\Assembly-CSharp.dll。
(2)用VS建立控制台应用程序,将要加密的dll放置于工程目录中,并进行加密(比如下图代码将dll转换成字节流并将字节偏移1位)。
加密后的dll用反编译工具打开会报错。至此加密已经搞定,接下来重头戏就是修改mono源码并重编译了~
2、在CentOS 6.6中修改mono源码并重编译
这是一个漫长的征途,咱们从头一步一步来:
(1)安装CentOS虚拟机
此处建议安装CentOS 6.6 32位虚拟机,之前试过Ubuntu的32位跟64位,始终没能成功编译。CentOS虚拟机种子下载地址:
http://pan.baidu.com/s/1qWmTbx6
(2)下载安装Xshell(该步骤可省略)
“工欲善其事必先利其器”,因为Xshell操作起来比较方便,所以此处有安装Xshell跟Xftp,心急的童鞋可以略过。
Xshell和Xftp下载地址:
http://pan.baidu.com/s/1jGKpmCI
如果打算也用Xshell操作的话,记得将Backspace按键重新设置一下,因为默认该按键不是退格删除,用起来很心塞。设置方法:点击“文件”-“属性”,在打开的窗口中选择“键盘”,然后在右侧的BACKSPACE键序列中勾选“ASCII 127”即可。参见下图:
Xshell安装完新建连接,输入CentOS的IP地址进行连接,成功连接后就可以直接在Xshell窗口中操作虚拟机了。
(3)下载mono源码,下载的版本要跟项目开发时用的Unity版本一致。我下载的是5.0,亲测可编译成功。下图是说明如何进行版本的选取。
下载地址:https://github.com/Unity-Technologies/mono
(4)至此前期准备工作已经完成。接下来将mono源码的zip拷贝至CentOS(目录/home/ouyxq/mono-unity-5.0),并用unzip命令解压。解压完成后cd到解压后mono的根目录下,在命令行中执行:
./autogen.sh --prefix=/usr/local;
该命令会检查编译需要的环境,如果有缺失会进行提示,接下来基本上就是根据提示进行环境的安装。提示出错不可怕,可怕的是压根不知道错哪儿了,所以这行命令实在是相当良心啊~
(5)因为许多目录都需要权限,所以在此先输入su–l root进入root用户,再在mono根目录下,根据错误提示安装缺少的组件:
yum installautoconf
yum installlibtool
yumintall –y gcc-c++
yum install bison
yum install –ygettext
yum install glib2-devel.i686 #注意此处安装的是glib开发包
yum installperl #安装perl
yum install git #安装git,后面编译的脚本会用到git去下载(6)安装完以上包之后再次执行./autogen.sh --prefix=/usr/local 不再提示环境缺失了。
(7)配置NDK环境变量。可以不用提前下载NDK,因为编译的脚本会自动去下载,速度还不错。默认下载的目录是/root/android-ndk_auto-r9,省事的话就直接把环境变量配置到此目录好了(否则会提示Failed to locate Android NDK)。在Xshell命令行输入:
ANDROID_NDK_ROOT=/root/android-ndk_auto-r9
export ANDROID_NDK_ROOT
再输入echo $ANDROID_NDK_ROOT确保环境变量配置成功。
(8)接下来要真正执行编译的sh脚本了,在mono根目录下输入:
sh external/buildscripts/build_runtime_android.sh
此时会看到错误提示如下:
Can't exec "lwp-download": No such file ordirectory at /home/ouyxq/mono-unity-5.0/external/buildscripts/PrepareAndroidSDK.pm line 379.
原因是缺少perl的lwp模块,解决办法,先安装cpan:
yum install perl-CPAN-i686
安装完成后输入cpan进入cpan命令,再安装lwp,输入
install LWP
Install Bundle::LWP
安装完成后输入quit退出cpan命令。再输入lwp-download检测是否安装成功(如下图即为成功):
(9)解决掉两个错误,开心地再次执行sh external/buildscripts/build_runtime_android.sh,然后你会惊喜地发现……又出错了。这个错误是经典的错误,之前在这里折腾了好几天啊啊啊!!!但是!不要遭急!我们很快可以一雪前耻~~先看错误提示:
对,就是这个可恶的envsetup.sh: file not found。让我揭开你神秘的面纱来。其实我参照的视频里,大神编译到这里,虽然报了这个错,但是实际上这个envsetup.sh文件有在编译过程中生成,生成的目录就在mono根目录。之所以报错是因为build_runtime_android.sh有点蠢,它死活找不到这个sh,所以需要修改一下代码里的路径指向。
但鉴于我出错的情况比较特殊,压根木有这个envsetup.sh,辣摸我就自己弄一个好了。请教了另一位大神,发现其实这个sh里面就一句代码,就是导出NDK的路径。所以自己新建一个envsetup.sh,把下面的语句加上去,再把sh保存到mono根目录下。
export ANDROID_NDK_ROOT=/root/android-ndk_auto-r9
再接下来要去修改build_runtime_android.sh,将路径改成envsetup.sh所在的绝对路径。这个拦路虎就被解决掉啦~
(10)然后继续执行sh external/buildscripts/build_runtime_android.sh(记得一定要在mono根目录下执行这个脚本),你会再次惊喜地发现,遇到了第二大拦路虎!!/usr/bin/env:perl -w: Nosuch file or directory
为了表达内心的愤怒,我要再把报错的图贴上来:
来吧,拔出你的剑,杀掉这只拦路虎,成功已经向你招手了~
解决办法:进入到external/ android_krait_signal_handler目录,编辑目录下的build.pl,将第一行改成如下:
(11)添加解密算法
到这里所有的编译错误算是全都解决掉啦。接下来不要忘记,编译的最初目的是为了对加密的dll做解密。所以要修改image.c添加解密算法,在/mono/metadata/image.c里面找到mono_image_open_from_data_with_name ,解密算法跟前面对dll的加密算法对应,直接让字节下标为1的字节-1即可:
if(strstr(name,"Assembly-CSharp.dll")){
data[0]-=1;
}
另外,为了节省编译时间,可以注释掉两行代码(用#号注释),因为没有必要打包Arm5跟Arm6平台,保留Arm7的就够了:
#clean_build “$CCFLAGS_ARMv5_CPU” “$LDFLAGS_ARMv5″ “$OUTDIR/armv5″
#clean_build “$CCFLAGS_ARMv6_VFP” “$LDFLAGS_ARMv5″ “$OUTDIR/armv6_vfp”
(13)最后,激动人心的时候到啦~再回到mono根目录,再次执行sh external/buildscripts/build_runtime_android.sh
可以看到已经成功在编译啦~~~刷屏的赶脚真好~~ T_T
大概5分钟左右吧,具体时间取决于虚拟机配置。编译完成。可以在mono目录下的builds/embedruntimes/android下找到Arm7和x86平台的libmono.so。解密的工作也就完成啦~
(14)最后这一步基本上是尾声了。将刚刚编译完的libmono.so替换掉之前导出的android的libs目录下对应的libmono.so。再用Eclipse打包出apk,导入手机运行,你就会开心地发现,程序可以正常地运行啦,而且源代码dll不能被反编译哟( ^_^)~
虽然逆向高手们还是可以通过ida找到你的解密代码进行破解(道高一尺魔高一丈),但毕竟任何反编译工具都无法看到你的源码了。可以适当增加加密算法的难度,另外雨林大神提供了对包含解密算法的so档进行加密的办法,有时间也要尝试看看~应用安全本来就是“路漫漫其修远兮”,诸君共勉吧~
参考文章:http://www.xuanyusong.com/archives/3553?utm_source=tuicool