您的位置:首页 > 移动开发 > Unity3D

编译unity-mono( 写给超级初学者的朋友)

2016-12-02 17:38 337 查看
前言:看文章切忌心浮气躁.

为什么要编译mono?相比看到这篇文章的朋友应该都不需要再多问为什么,那么为了呼应标题,笔者还是想再简明扼要的阐述一下,以便不知道干啥的朋友还可以知道要干啥.

unity生成的apk包,实际上就是一个压缩文件,我们可以直接解压出来,解压出来之后我们可以找到这样的一个目录:assets\bin\Data\Managed,在这个目录之下都是一些dll,然后这些dll是什么呢?听笔者接着说,倘若我们在unity里边有使用到dll,使用到的dll就会被打包放到这里,再这之中你或许还会看到一个名为Assembly-CSharp的DLL,为什么我这里用或许这样的字眼,是因为倘若你的整个unity工程若是没有脚本文件就不会有这个dll的产生,什么叫做没有脚本文件?举个例子就是:新建一个unity工程,一个脚本都不创建,然后就打包。

那,有的读者可能就会想了,这和为什么要编译mono有什么关系呐!别着急,正在分析中ing

好了,有脚本才会有这个名为Assembly-CSharp的DLL,那么有的读者会不会就会联想是否我们所有的脚本文件都是被打包到这个DLL的。是的,没有错,就是在这个CSharp程序集中,那么我们的重点也随之来了,倘若别人把这个dll拿去反编译了,我们的代码岂不是分分钟就别别人看到,现在反编译DLL的工具那么多,那么牛逼,网上一搜一堆堆的,有兴趣的读者可以自行尝试一下。

到此,或许很多读者最直接想到的不是为什么要编译mono,映入脑海中的而是怎么样才能不让别人反编译出我们这个dll。实际上这两个问题是想关联的,为什么会这么说?其实道理很浅显,首先我们怎么才能防止我们的dll不被人看到里边的源码,这个很简单,既然反编译是读取dll,那我要是将dll的文件结构给破坏掉,反编译的工具还能读取出来?显然是不能的,这也就我们通常所说的加密或者混淆。至于具体怎么做,我下边会给出,仅作为参考... 。 哇咔咔卡

那好了,解决了dll不被人反编译出来的问题,也就是说这个Assembly-CSharp的DLL文件结构已经被破坏,那,我们的apk还能正常的启用? 注意,这里我说的是是否能正常启动并不是说是否能正常安装,修改过的apk必须要重新签名一下才能被正常的安装,否则是安装不上,至于为什么,读者可以自行百度,我的个人理解不一定对,但,要我实现的话这也算的上是一种策略:大致我们原本的app应该会有一个类似MD5的值保存在app内部,而当android系统安装该app的时候会计算这个app的MD5值与原始MD5值进行比对,match成功则判断没有改动过,就可以正常安装,而签名就是类似于一个篡改AppMD5值的过程,计算出修改过后app的MD5值替换掉原本的MD5,所以,修改过的App一定要经过签名才能使用。然而,我这里想说的是将Assembly-CSharp修改过后这个APP是否能正常启用。

其实,读者只要认真想想的话,根据上边阐述的,应该自行都能想到答案。

既然,Assembly-CSharp程序集仅仅是存储了我们的脚本文件,这个文件被损坏掉的话,顶多是所有脚本全部失效,应该是不会影响正常启用的。很聪明,能想到这里,没有错,确实是这样,感兴趣的读者可以去自行try一下,万一我是骗子呐。此时的我正在一阵阴冷冷的笑....

我是不是越来越跑题了,有木有读者这样想.但,其实不然,要相信我...

既然说Assembly-CSharp被修改了,所有的脚本就都失效了,那怎么样才能保证不失效呢?

这又得从那个月黑风高的夜晚说起,话说,unity为什么可以做到跨平台,是因为在unity中使用C#脚本开发的代码底层都是运行在一个统称为"运行时"的虚拟执行系统上,所有的C#代码都被这个“运行时”中的一个名为"即时编译器"的组件再编译为各个平台的原生代码,unity能跨平台的原因就是实现了各个平台的“即时编译器”(C#代码 ->中间语言->各个平台的原生代码,目前是这样,后边好像会推出IL2CPP来代替mono,具体IL2CPP有什么特别之处,看官可以自行百度下,这里不是重点),大致了解了这个之后,我们的重点也就悄悄的来了,就是,这个“运行时”就是我们的mono,可能很多初学的朋友还是很难理解这个东西,不用怕,我再来解释一番:不知道读者是否熟悉net
framework,什么是net framework,通俗点说它就是C#语言赖以生存的环境,简而言之,你用C#语言开发的应用若是在没有安装net framework的机子上跑,必然是跑不起来的,毕竟它不是C或者C++直接就可以编译链接成硬件能够直接处理的机器语言,有接触过单片机或者嵌入式的朋友应该很容易就能理解。C#语言是被编译器比方说VS编译为中间语言,然后这个中间语言是运行在“运行时”的一个虚拟执行系统上,这个虚拟执行系统不单单负责把中间语言编译为机器码,还负责很多东西,比方,GC(垃圾回收),公共语言规范,平台可移植性等等等等。我这边只是大致的阐述一下,感兴趣的朋友可以去了解下C#本质论。然而,这一切都是包含在.net
framework中的,所以说,C#脱离不了.net平台,好比汽车跟汽油的关系。但,这跟mono有什么关系呢,其实,mono就是从net framework衍生出来的,只不过mono可以跨平台运行,linux,windows,mac都可以运行,也就是说mono是一个可以跨平台运行的net framework,那么也就是说我们的Assembly-CSharp是在我们的mono上运行的,那问题来了,这个mono在哪里呢?各位看官别着急,答案马上揭晓.

曾记否,我们上边提到将apk解压出来,解压之后,我们在lib目录下还可以看到一个x86文件夹和一个armeabi-v7a文件夹,这两个文件夹里边都有一个叫做libmono的文件,这就是mono编译出来的产物,也就是说Assembly-CSharp是被这个叫做libmono的家伙所加载跟执行的,那为什么会有两个呢?是因为针对不同cpu架构的机子:x86架构和arm7架构分别做处理,这我们无需关心,最终编译mono也会有这两个,我们替换就好了。这里讲到要编译mono,我们最终的重点也就来了,就是因为我们加密了我们的Assembly-CSharp,所以,导致了libmono.so“不认识”这个文件了,从而加载失败,也就是说我们所有的脚本就都失效了,所以说我们需要在改写mono的源代码,附加上我们的解密算法,编译生成一个libmono.so的文件,替换原本的libmono.so,使之可以正确的识别我们加了密的Assembly-CSharp.

又曾记否,上边我们提高编译unity-mono个加密dll是想关联的,道理就是这么来的

到此,我们已经知道了why,接着我们就要来how,就是怎么做.. 那么请各位看官继续跟着我的步伐,你绝对能找到出路.

首先,我先说说环境,我希望读者能跟我保持一致,因为不同的环境会有差异性,别小看这点差异性,往往就这点差异会让你抓耳绕揌良久。苦涩的风吹过脸庞的感觉.....

既然是编译unity-mono,那这个unity-mono必然是一个项目,就像你通过VS新建一个控制台应用程序一样,代码写完了还得编译,这个项目在哪里呢,这个项目是开源的,放在git-hub上的,这里贴出链接:https://github.com/Unity-Technologies/mono/tree/unity-5.3
 我编译的是5.3的版本,这个得对于你开发所使用的unity的版本,我用unity5.3x做开发的。对于编译所使用的平台,我使用的是linux,具体是Ubuntu
16.04 Desktop (32-bit),这个去官网下载,使用64bit也可以,但是没有32bit方便,还需要比32bit的多装几个库,虚拟机我使用的是VMWare12 Pro.

在此:提醒一点,整个过程务必要有网络的存在,否则有的软件包无法得到更新,然后就尴尬了。

到此,大环境是准备完毕了。若是对于有的看官并没有接触过linux系统,也不用太担心看不懂的问题,因为我使用到的每一个命令我都会做解释。

ok,那我们开始准备搭建小环境,也就是搭建编译unity-mono所需要的库,为什么需要搭建呢?你想想,假如windows上没有任何跟编程相关的软件,你能开发windows应用程序?所以,通俗的讲,这一切也就是不断的装各式各样的软件包,这些软件包是能成功编译unity-mono的必要环境。

第一步,在虚拟机中能安装UbutuOS,这过程中基本上就是点击下一步,没什么难度,完事之后记住你设置的账户和密码就好了。

到这,假设Ubuntu安装成功,并且已经成功来到桌面,可以右键点击选择OpenTerminal的方式来打开终端,也可以直接按快捷键Ctrl+Atl+T来打开,想必终端是什么就不需要在解释了吧。那我们接着要干嘛呢?首要的就是把我们的unity-mono拷贝到这个虚拟机就中,怎么拷贝呐,当然你可以直接在虚拟中下载,除此之外,我使用的是Winscp这个软件,这里贴出下载地址:http://rj.baidu.com/soft/detail/15150.html?ald。注意:只有虚拟机和主机在同一台机子上才能使用这个连接到Ubuntu,另外,这需要Ubuntu开启SSH服务才行,否则你是连接不上的,所以我们首先在Ubuntu中装上SSH服务,打开终端,切记要有网络,我们输入apt-get
install ssh 然后点击回车,顺利的话,你会看到[Y/n]的字眼。这句命令就是更新ssh软件包,[Y/n]字眼询问你是否要下载并安装,点击Y按下回车,啪啪啪,静静的等着安装完毕。若是不幸运的话,你会看到:Could not open lock file /var/lib/dpkg/lock - open之类的字眼,这是在说资源被占用无法启用它来进行下载,就类似于下载器被占用着,导致此时其它进程无法享用它,如何解决呢,把这一行百度,立马就有答案,我这就不说了。也就是两行命令的事情,若是还解决不了,建议重启一下系统在try一下.

然后,我们又假设,在ssh服务成功开启的状态下,并且你也成功的将unity-mono-5.3.zip从win上拷贝到Ubuntu上。放在你想放的任意位置,我这边放在桌面上的

首先接下来的第一步我们是需要将之解压出来,我这边也是解压到桌面的,通过cd xxx的命令来到桌面,再ls命令查看一下桌面是否真的存在这个压缩包,确定存在,再通过解压命令 unzip xxx.zip的方式将之解压在当前目录,也就还是在桌面。在屏幕唰唰唰之后,可以看到桌面上多出来一个文件夹,在终端中通过cd命令进入这个文件夹,在用ls命令查看一下这个文件夹下所有的文件,可以看到里边存在一个autogen.sh的文件,这是一个批处理文件,是帮我们检查编译mono-unity所需要的环境的,我们要运行它,通过./autogen.sh来执行./代表的就是当前目录,因为你是第一次,恩,没错,你的第一次,怎么有点邪恶的感觉,哈哈哈~
 因为是第一次,所以有的库你必然是缺失的,所以执行这个批处理文件你会收到三个错误,一个是提示你必须安装autoconf以编译mono,一个是提示你必须安装libtool,还有一个是提示你必须安装automake。

好了,到这一步,你离成功又近了一步,既然提示缺少那就安装呗,apt-get install autoconf安装autoconf,同样的方式安装其他两个,顺利的话你三个都安装完毕。很兴奋...。再去执行那个autogen.sh的批处理文件,因为是第一次,所以也不知道会发生什么,但,想想应该会有大动静,但,现实是很骨感的,瞬间就有了结果,还是提示你需要安装libtool。(没遇到这个最好,反正我死活都会有遇到,而且还在这里坑了好久) 刚刚明明安装过了,为什么还会提示,是不是可以通过什么样的命令来检查一下我是否有安装libtool呢?是吧,这里给出命令:apt-show-versions
xxx.  应该还会提示你安装 show-versions这个包,用命令安装一下就可以了,然后再次使用apt-show-versions libtool ,会发现libtool的版本号也出来了,这说明确实是正确安装了。寻寻觅觅良久,又通过各种方式安装libtool,最终发现还是提示这个错误,崩溃。后来,感谢我的舍友,发现将libtool开头的所有文件都安装上 即使用apt-get install libtool* 大概有一百来M,才解决了这个问题,似乎是需要安装一个libtool-bin的库,这就是坑,也没有提示只提示了一个libtool,谁知道该安装什么呢?又或许是我的无知...
(在Ubuntu14.04-32bit下边不会存在这个问题)

libtool的问题解决了,再次执行./autogen.sh,可以发现屏幕唰唰唰,以为检查环境成功,哪知道你又错了,你会看到一个bison的字眼,提示你需要安装这个库,安装就是,再次执行,提示你还需要安装至少glib 2.0-2.40,安装一个glib2.0就好了

到此,再去运行./autogen.sh. 等着屏幕唰唰唰,最后在屏幕的下方会出现一个提示你执行'make'的信息 ,看到这个,就说明你的环境大致安装成功了,可以进行下一步的操作了,为什么说是大致呐,因为还是不全。不要紧 我们接着来。 

我们cd 进去到mono-unity-5.3/external/buildscripts目录下,ls命令一下我们可以看到一个build_runtime_android.sh的批处理文件,我们需要将执行它,它会自动的帮我们编译mono,当然,我们不是在当前目录下编译,而是需要将之拷贝到mono-unity-5.3的目录下,使用cp命令就可以了:cp 需要移动的文件 目标路径。拷贝完毕后我们再次cd到mono-unity-5.3的路径去执行它,直接使用命令:./build_runtime_android.sh
。  ./代表当前目录

然而,因为你是第一次,所以它会提醒你安装NDK,并且还需要去配置NDK的环境变量,这里需要注意的是,它会自动的帮你去下载对应版本的android_ndk ,若 你没有配置ANDROID_NDK_ROOT环境变量,它会将下载来的东西删除掉,所以,首先你应该去配置下android_ndk的环境变量,倘若,你还处于在下载的过程,可以使用ctrl+C组合按键进行中断,然后去配置下环境变量,配置环境变量有好几种方式,我这边编辑的是~/.bashrc这个文本文件,使用vim 进行编辑,因为你是第一次,所以vim这个工具你应该还没有安装,不过没有关系,你可以使用Ubuntu自带的gedit来进行编辑:
gedit ~/.bashrc 然后就跟windows操作记事本一模一样,此时我们只需要在结尾加上一句export ANDROID_NDK_ROOT=/home/test/android-ndk_auto_r10e.  说明:路径是任意的,你想安装在什么位置就安装在写什么位置。完事之后保存一下,然后再终端中输入 source ~/.bashrc的命令来使得环境变量生效。这完事之后我们可以使用echo $ANDROID_NDK_ROOT命令来查看一下环境变量是否配置成功,假如得到的是你所配置的路径,那就说明配置成功了,你离编译成功又近了一步。OK,此时我们再到mono-unity-5.3的路径再去执行build_runtime_android.sh.
 然后,屏幕唰唰唰,你会看到它在下载android_ndk, 保存路径跟安装路径,在开始的时候就有打印出来,而刚才配置的哦android_ndk_root好像是安装路径,我给忘记了有点记不清了... 呼呼呼 好尴尬.  好在这并不是重点,都打印出来了自己看看就知道.

到这,有木有读者想着说这就成功了,是不是很简单,我可以很负责任的告诉你,你又错了,到最后你应该会看到一个C compiler 字眼的错误,翻看日志信息,最终发现原来是还少了一个git的库没有安装,使用命令apt-get install git安装一下,安装完毕之后,再次去执行android_runtime_android.sh批处理文件,注意一开始就会打印出一句带有android_krait_signal_handler话,找到文件夹,路径也是在这句话中包含着,我没记错应该是在android_runtime_android.sh的上级的上级目录下,为什么需要去找到这个目录,是因为此时你编译还是会出现那个C
complier的字眼错误,但真正的错误并不是在这里,我们可以将鼠标往上滑,翻看刚开始答应的日志,可以看到perl -w 什么的字眼,问题就出在了这里,它找不到perl这样的命令,我开始还在这里绕了许久,还以为是什么环境变量的问题,真是淡淡的忧伤,后来才发现原来只需要更改一下文本里边的内容就搞定了,而需要更改的文件就在android_krait_signal_handler里边,这里边有个就做build.pl的文件,我们编辑它,将第一行的env去掉即可为这样:#!/usr/bin/perl -w 然后保存,再次去编译build_runtime_android.sh即可,屏幕刷刷唰,这大概需要等待好几分钟。

完事后,若是成功,会有一句话输出,意思是告诉你生成的libmono.so所在 的文件夹, 是在mono-unity-5.3/builds/embedruntimes/android目录下,一个对应着x86架构,一个对应着arm7架构。

呼呼呼,这就是编译unity-mono,将此生成的libmono.so替换掉安卓apk包中的libmono.so就可以了,但,各位看官想想,这样替换有木有用,这样替换当然是没有用的,因为我们并没有修改源代码,并没有在读取Assembly-CSharp的时候附加上解密算法,所以,这样生成的libmono.so跟我们要替换的是一模一样的,所以,接下来我们就需要修改源码再进行编译。

那么源码在哪里呢?由于天也不早了,读者可以阅读这边文章:http://www.xuanyusong.com/archives/3553。  

结尾提一下注意点:若是使用64bit的Ubuntu还需要安装以下库:libc6-dev-i386 和 install lib32z1。个人强烈建议使用32bit的OS来编译

时间真的不早了,流浪的生涯还得继续。  欢迎拍砖,拿起板砖狠狠地拍,狠拍... 

QQ:2306798290

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Unity mono 解密 加密 apk