2017-05-18 15:57:00 KiTok 阅读数 17588
  • unity3D-游戏/AR/VR在线就业班

    本套课程是一套完整的 Unity3D-游戏/AR/VR 学习课程,具体的课程内容包括《C#语言》、《Unity引擎》、《编程思想》,《商业级项目实践》等开发课程,引导您一步步循序渐进、由易到难,终获得Unity 3D/游戏/AR/VR工程师的岗位技能。

    13036 人正在学习 去看看 宋晓波

Unity3D加密教程


    引言 :

         为了防止别人通过反编译来破解修改自己的游戏项目。可以通过两种比较成熟的方案来预防。一种是混淆,另一种就是加密(加壳)。由于加壳后的文件反编译比混淆后的难度更大,所以我们这里采取加密的方法对PC平台和安卓平台的应用进行加密。

         那么我们去加密什么呢?    Unity通过Mono来达到跨平台的效果。在Build编译时会将你编写的code转为符合CLI的CIL(Common Intermediate Language,中文:中间语言),并且主要的Code会编译在Assembly-CSharp.dll里面,然后再有mono来加载,解析,执行。Mono加载Assembly-CSharp.dll的时候就是读取文件到内存中,和读取一个游戏资源文件没多大区别。所以我们要做的就是把这个Assembly-CSharp.dll文件加密,简单点的可以修改文件的一个字节或者位移一下,破坏其原有的结构。就无法使之通过例如Reflector9VSPro去反编译,因为此时的Assembly-CSharp.dll已经不是一个正确的dll文件了。可尴尬的是,别人没法反编译出文件内容了,Mono自己也不认识了。这将导致,游戏无法运行。所以,我们在对其加密的同时也要加入相应的解密算法。

         image.c脚本在游戏运行时会去主动加载Assembly-CSharp.dll文件。那么我们在image.c相应的方法里面加入解密算法,然后从新编译Mono,生成相应的程序集,来替换待解密项目中的相应文件。就可以达到游戏运行正常又安全的效果。

        So ,Follow me to see.

Window篇

加密Assembly-CSharp.dll :

需要工具:

  1. Reflector9VSPro:反编译工具:用于成果测试。

  2. xxtea:此教程所用的第三方加密解密算法:用于加密解密。

  3. MinGw:使用gcc编译:用于制作加密工具。

  1. 首先下载需要工具的工具3。进行安装配置。可在cmd窗口中用“gcc -v”指令来查看安装结果。
  2. 下载工具2。文件夹中有xxtea.h、xxtea.c两个文件。这两个就是加密解密的代码。
    • 创建新文件夹“encrypt”,把这两个文件放在“encrypt”文件夹中。
    • 新建C语言脚本“EncryptManage.c”,同样放在“encrypt”中。脚本内容:
  #include <stdio.h>  
  #include <string.h>  
  #include <stdlib.h>  
  #include "xxtea.h"  
  #define SIZE 1024*1024*10  
  void main()  
  {  
      FILEFILE *infp = 0;  
      if((infp=fopen("Assembly-CSharp.dll","rb"))==NULL)  
      {  
          printf("Assembly-CSharp.dll Read Error\n");//打开操作不成功  
          return;//结束程序的执行  
      }  
    
      //char buffer[SIZE];  
      char* buffer = (char*)malloc(sizeof(char)*SIZE);  
      memset(buffer,0,sizeof(char)*SIZE);  
    
      int rc = 0;  
      int total_len = 0;  
    
      total_len = fread(buffer , sizeof(unsigned char) , SIZE , infp);  
      printf("Read Assembly-CSharp Successfully and total_len : %d \n" , total_len);  
    
      //加密DLL  
      size_t len;  
      char* key = "123456";  //此处位密钥。可自由更改
      charchar *encrypt_data = xxtea_encrypt(buffer,total_len, key, &len);  
    
      printf("Encrypt Dll Successfully and len : %d\n" , len);  
    
      //写Dll  
      FILE* outfp = 0;  
      if((outfp=fopen("Assembly-CSharp_encrypt.dll","wb+"))==NULL)  
      {  
          printf("Assembly-CSharp_encrypt.dll Read Error\n");//打开操作不成功  
          return;//结束程序的执行  
      }  
    
      int rstCount = fwrite(encrypt_data , sizeof(unsigned char) , len , outfp);  
        
      fflush(outfp);  
    
      printf("Write len : %d\n", rstCount);  
    
      fclose(infp);  
      fclose(outfp);  
    
      free(buffer);  
      free(encrypt_data);  
  } 
  • 打开cmd窗口。cd到encrypt文件夹中。然后使用gcc编译EncryptManage.c文件。生成可自动化加密的exe文件"EncryptManage.exe"。
    代码为gcc xxtea.c EncryptManage.c –o EncryptManage
  1. Build PC平台的游戏项目。在生成的文件夹中找到我们需要加密的xxxxx\xxxx_Data\Managed\Assembly-CSharp.dll文件。把这个文件同样放在第二步中创建的encrypt文件夹中。
  2. 直接点击第二步创建的EcryptManage.exe文件。执行加密Assembly-CSharp.dll文件的操作。生成Assembly-CSharp_encrypt.dll文件。这个就是加密后的文件。把他从新名为原Assembly-CSharp.dll名称。放回他所在源目录。
  3. 使用Reflector9VSPro工具进行反编译Assembly-CSharp.dll。如果发现反编译失败。证明加密成功。此时可相应的运行游戏文件。会发现游戏也无法正常运行。

重编译可解密的mono.dll文件 :

需要工具:
注意:如果你希望编译顺利进行,不把时间浪费在一些坑上。就需要这些工具。
  1. Visual Studio 2010:去编译和修改mono项目:由于mono-unity官方项目使用VS2010创建的,所用使用vs2010会避免很多的冲突,在用VS2015的时候就会碰到配置,引用,平台工具集型号…等等问题,再加上其他各种未知问题,最后选择了VS2010版本,才成功。

  2. mono-unity-5.6:我在此用的时5.6的包,观者可根据需求下载相应版本的包:我们通过对它的修改添加,从编译。生成相应的mono.dll文件,用于解密。经过测试,可编译成功的版本有4.6,5.1,5.5,5.6

  1. 使用上文中的加密文件xxtea.c和xxtea.h复制到下载的mono的工程目录里,具体位置在mono-unity-5.6\mono\metadata文件夹下。

  2. 然后用vs2010打开工程文件mono-unity-5.6/msvc/mono.sln,打开之后,通过“解决方案资源管理器”找到libmono项,再将复制在mono-unity-5.6\mono\metadata文件夹中两个xxtea文件添加到libmono项中,并找到libmono下的image.c,打开,开始添加解密代码。

  3. 由上述引言可知,image.c就是我们要添加解密代码的文件。首先,添加引用头文件#include"xxtea.h"和#include <stddef.h>

  4. 在脚本中找到方法 “mono_image_open_from_data_with_name”。这个就是加载Assembly-CSharp.dll的入口。那么我们就在此方法中添加我们的解密代码。
    代码如下:

MonoImage *  
mono_image_open_from_data_with_name (charchar *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status,    gboolean refonly, const charchar *name)  
  {  
      MonoCLIImageInfo *iinfo;  
      MonoImage *image;  
      charchar *datac;  
    
    //第一个参数data指向运行时Assembly-CSharp.dll的内存地址
      if (!data || !data_len) {  
          if (status)  
              *status = MONO_IMAGE_IMAGE_INVALID;  
          return NULL;  
      }  
    
     //这是添加的代码,开始   你也可以换成自己想要的解密方法
     if(name != NULL)
     {
      if (strstr(name, "Assembly-CSharp.dll")) {  
          char* key = "123456";     //此处密钥需要对应加密时候所创建的密钥
          size_t len;  
          char* decryptData = (charchar *)xxtea_decrypt(data, data_len,key, &len);  
          int i = 0;  
          for (i = 0; i < len; ++i)  
          {  
              data[i] = decryptData[i];  
          }  
          g_free(decryptData);  
    
          data_len = len;  
      } 
    }
     //这是添加的代码,结束
      datac = data;  

5. 最后,我们开始编译工程。
* 打开 Visual Studio Command Prompt(2010)
* cd 到mono-unity-5.6\msvc目录中
* 执行msbuild.exe mono.sln /p:Configuration=Release_eglib命令

注意:直接打开mono.sln解决方案,通过Visual Studio直接生成是编译不了的,这是个坑。

6.我在这里用了54秒就编译成功了。生成的dll位置在mono\builds\embedruntimes\win32\mono.dll。(63位的mono.dll文件要用Visual Studio x64 Win64 命令提示(2010)去编译)

7. 最后把你编译出来的mono.dll文件复制到你的项目包中,替换Mono文件夹中的源mono.dll文件。
好了,OK。运行游戏,完美运行。再用反编译工具去反编译Assembly-CSharp.dll。发现无法反编译。


Android篇

注意:由于windows和ubuntu平台中对Assembly-CSharp.dll的加密操作是一样的,所用不做多余叙述,Assembly-CSharp.dll的加密可以直接使用windows平台加密后的Assembly-CSharp.dll文件。 在window篇中我们要使用的是编译后的mono.dll文件。但是在Android项目中,我们要使用的是libmono.so文件。其他需要操作的对象文件都一样。所以我们只需要使用Ubuntu32为系统去重编译可解密的libmono.so文件即可。

Ubuntu 32位虚拟系统搭建:

需要工具:

  1. Ubuntu32位:ubuntu系统:由于windows上面比较麻烦,而且错误特别多。而ubuntu64位不选择的原因是坑很多。用32位系统至少可以让坑少一半。

  2. VMware Workstation :桌面虚拟计算机软件:用于搭载Ubuntu系统。

  3. android-ndk-r10e-linux 32位:基于linux系统的NDK:NDK的版本是根据项目需求下载的,此处操作的mono-unity-5.6的mono项目包,此项目要求使用“r10e”版本的NDK。

  1. 通过VMware Workstation 搭建Ubuntu虚拟环境。
  2. 安装编译所需相关工具:
    • autoconf
    • automake
    • bison
    • gcc
    • gettext
    • git    //编译时,项目会需要git命令去下载依赖文件。
    • glib >=2.0    //编译所需库文件。
    • libtool    //如果你是64为的NDK。由于交叉编译工具是32为的。则需要安装的libtool也是32为的。所以,这个工具在安装的时候要使用 sudo apt-get install libtool*命令安装,注意要加“  *  ”。这样可以安装整个libtool-bin库。非则的话就算安装了libtool也会一直提示没有安装libtool。在32位系统下不存在这个问题。
    • make    //编译工具。
    • perl    //用于运行pl脚本。

命令为sudo apt-get install autoconf automake bison build-essential gettext git libglib2.0 libtool* perl
3. 配置NDK的环境,配置步骤:
a. 在终端输入sudo gedit ~/.bashrc。打开环境变量配置文件。
b. 在文件末端直接加入环境变量:

 NDK_ROOT=/home/xxxx/xxxx/android-ndk-r10e   
 NDK=$NDK_ROOT
 ANDROID_NDK_ROOT=$NDK_ROOT
 export NDK_ROOT NDK ANDROID_NDK_ROOT

c. 保存并且使环境生效:` source ~/.bashrc ``

编译前的文件修改 :

需要工具:

  1. mono-unity-5.6:观者可根据项目需求下载相应的包。

  1. 下载mono-unity-5.6文件之后。这个文件夹的上层级最少要有两层。如果不够,则新建空文件夹用于存放此文件夹。
    原因:在build_runtime_android.sh文件中,大概56行有 :KRAIT_PATCH_PATH="${CWD}/../../android_krait_signal_handler/build" 。这个表示,在编译的时候会下载依赖文件“android_krait_signal_handler”。如果无法保证上层级在两层以上,也可以更改这行代码。
  2. 在下载的mono-unity-5.6文件夹中。找到build_runtime_android.sh文件。具体位置在\mono-unity-5.6\external\buildscripts文件夹中。把他放在\mono-unity-5.6\根目录中。
  3. 打开 build_runtime_android.sh文件。在15行perl ${BUILDSCRIPTSDIR}/PrepareAndroidSDK.pl -ndk=r10e -env=envsetup.sh && source envsetup.sh中。 -ndk=r10e描述的是所需ndk版本。
  4. 修改build_runtime_android.sh文件内容:
    • 在文件第6行的export ANDROID_PLATFORM=android-9下面添加exportANDROID_NDK_ROOT=/home/xxxx/xxxx/android-ndk-r10e。为防止不必要的错误,手动指定ndk目录。
    • 如果出现无法找到 envsetuo.sh文件的错误。则需要手动指定envsetuo.sh文件所在目录。第15行perl ${BUILDSCRIPTSDIR}/PrepareAndroidSDK.pl -ndk=r10e -env=envsetup.sh && source envsetup.sh末端的``source中直接指定文件目录source xxxx\xxxx\mono-unity-5.6\envsetup.sh`。
    • 在文件第74行:-fpic -g -funwind-tables \中。把-g改为-O2(O0,O1,O2,O3分为好几个压缩档次)。通过更改这个可以编译出release版本。会比debug版本体积更小。
    • 找到第154到156行:
      #clean_build "$CCFLAGS_ARMv5_CPU" "$LDFLAGS_ARMv5" "$OUTDIR/armv5" 
      #clean_build "$CCFLAGS_ARMv6_VFP" "$LDFLAGS_ARMv5" "$OUTDIR/armv6_vfp"
      clean_build "$CCFLAGS_ARMv7_VFP" "$LDFLAGS_ARMv7" "$OUTDIR/armv7a"
    
    注释掉前两行。我们只需要armeabi-v7a和x86类型的libmono.so文件。所以注释掉可以节省编译时间,
  1. 修改build_runtime_android_x86.sh文件内容:

    • \mono-unity-5.6\external\buildscripts文件夹中找到:build_runtime_android_x86.sh文件。打开准备修改。
    • 同build_runtime_android.sh的修改一样。在第6行下面添加NDK目录:exportANDROID_NDK_ROOT=/home/xxxx/xxxx/android-ndk-r10e
    • 修改第71行:-fpic -g\。去掉-g改为-fpic \。为了防止x86下的手机进入游戏卡顿的情况。
  2. 注意: 如果你下载的是32为的NDK可以忽略此步骤。修改PrepareAndroidSDK.pm文件内容。文件在/mono-unity-5.6/external/buildscripts/下面。

    • 直接翻到最后的第435行中,找到PrepareNDK方法。
    sub PrepareNDK
       {
     	my ($ndk) = @_;
    	my $ndk_root = $ENV{$NDK_ROOT_ENV};
     	$ndk_root = $1 if($ndk_root=~/(.*)\/$/);
    
         # 读取NDK目录下的RELEASE.TXT文件以查看NDK版本号
    	if (-e $ndk_root and open RELEASE, "<", catfile("$ndk_root", "RELEASE.TXT"))
    		{
    			my @content = <RELEASE>;
    			close RELEASE;
    			chomp(@content);
    			my $current = $content[0];
    			print "\tCurrently installed = " . $current . "\n";
    	
    	         
    			# remove the possible '(64-bit)' from the end
    			#如果你下载的NDK是Linux 64-bit NDK,它的版本号是”  r10e-rc4(64-bit) “。那么将会在次数出错。程序将一直找不到你的NDK。
    			#所以需要修改下面代码为:`my @curr_arr = split(/\-|\s/, $current)`
    			#或者直接修改NDK目录下RELEASE.TXT文件内容为:` r10e (64-bit) `或者 ` r10e` 
    			my @curr_arr = split(' ', $current);
    			$current = $curr_arr[0];
    			
    			if ($ndk eq $current)
    			{
    				print "\tNDK '$ndk' is already installed\n";
    				return;
    			}
    	   .....
    }
    
  1. 检查编译所需环境是否合格。

    • 方法一:打开终端。cd 到mono-unity-5.6目录中,使用管理员权限执行autogen.sh文件。命令为:sudo ./autogen.sh。这是个批处理文件,帮我们检查编译mono-unity所需要的环境。如果出现缺失库的错误,那么根据错误进行相应修改和安装。这个文件会帮你执行configure,make,make clean,make distclean等命令。
    • 方法二:在终端中cd到mono-unity-5.6目录中。使用管理员权限执行sudo ./configure --prefix=/usr/bin命令。也是检查编译环境是否合格,如何没有合格,会报错。如果合格,则会他提示你执行make指令。到了这步,说明你的环境大致安装完成了。
  2. 开始第一次编译。管理员身份执行复制在mono-unity-5.6根目录下的build_runtime_android.sh文件,命令为:sudo ./ build_runtime_android.sh不要使用"sudo sh build_runtime_android.sh "去执行。第一次编译通常情况下都会碰到/usr/bin/env: perl -w: No such file or directory的错误。没关系。这次编译只是为了下载krait-signal-handler依赖文件。

  3. 如果你出现上面8所述的/usr/bin/env: perl -w: No such file or directory错误。那么打开刚才下载的krait-signal-handler文件夹。找到里面的build.pl文件。修改第一行#!/usr/bin/env perl -w#!/usr/bin/perl -w

  4. 注意: 如果你下载的是32为的NDK可以忽略此步骤。在修改完上述9中所述的错误之后。还需要用/mono-unity-5.6/external/buildscripts/目录下的PrepareAndroidSDK.pm替换/krait-signal-handler/目录下的PrepareAndroidSDK.pm

编译libmono.so文件及其之后的操作 :

  1. 开始第二次编译。 运行命令为:sudo ./ build_runtime_android.sh

    • 如果出错:查看/mono-unity-5.6/根目录下面的config.log文件。编译的错误会全部输出在此文件中。
    • 如果不出错,那么恭喜你。在/mono-unity-5.6/builds目录下就是编译出来的armv7a和x86的libmono.so文件。测试完成,那么加入解密代码。然后进行最终编译。
  2. 添加解密代码。还是找到image.c文件。在 “mono_image_open_from_data_with_name”方法中添加解密代码。此处和windows平台不同的是需要把xxtea.cxxtea.h的代码直接合并到image.c以及image.h中。

  3. 再次编译。成功生成libmono.so文件。然后复制到windows平台下。替换源游戏apk文件中相应的文件。包括。两个libmono.so以及Assembly-CSharp.dll文件。

从新打包APK :

需要工具:

  1. Apktool:反编译apk和从新打包apk工具。工具相关教程:Android apk反编译及重新打包流程



这里写图片描述

Hello ,I am 李本心明


首先谢谢大家的支持,其次如果你碰到什么其他问题的话,欢迎来 我自己的一个 讨论群559666429来(扫扫下面二维码或者点击群链接 Unity3D[ 交流&副业]CLUB ),大家一起找答案,共同进步 同时欢迎各大需求商入住,发布自己的需求,给群内伙伴提供副职,赚取外快。对了,资源的话,要在群公告里面找。

由于工作生活太忙了,对于大家的帮助时间已经没有之前那么充裕了。如果有志同道合的朋友,可以接受无偿的帮助别人,可以单独联系我,一块经营一下。
如果你有更好的经营方式也来练习我,加我QQ

在这里插入图片描述


2015-08-19 13:39:48 yxq408576080 阅读数 3587
  • unity3D-游戏/AR/VR在线就业班

    本套课程是一套完整的 Unity3D-游戏/AR/VR 学习课程,具体的课程内容包括《C#语言》、《Unity引擎》、《编程思想》,《商业级项目实践》等开发课程,引导您一步步循序渐进、由易到难,终获得Unity 3D/游戏/AR/VR工程师的岗位技能。

    13036 人正在学习 去看看 宋晓波

      为防止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;

}



(12)将debug模式改成release模式,不然打出来的so包体积会大一倍。要将external/buildscripts/build_runtime_android.sh和external/buildscripts/build_runtime_android_x86.sh都做修改。删掉CFLAGS里的-g参数,如下图:


 

另外,为了节省编译时间,可以注释掉两行代码(用#号注释),因为没有必要打包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

                    

2016-07-29 10:43:59 qq_22780533 阅读数 6727
  • unity3D-游戏/AR/VR在线就业班

    本套课程是一套完整的 Unity3D-游戏/AR/VR 学习课程,具体的课程内容包括《C#语言》、《Unity引擎》、《编程思想》,《商业级项目实践》等开发课程,引导您一步步循序渐进、由易到难,终获得Unity 3D/游戏/AR/VR工程师的岗位技能。

    13036 人正在学习 去看看 宋晓波

我们知道,Android架构中上层应用是以java来编写的,而底层则用C/C++编写。一般而言,上层android工程师在开发过程中,不会或很少涉及到C/C++层,但项目中一旦涉及到复杂的算法或耗时操作时(例如图像处理等),通常使用C/C++完成算法实现并提供给java层(通过JNI)调用,以此提升软件的运行效率。在这个过程中,C/C++所实现的代码以及JNI调用相关的代码被打包为.so库,这即是所谓的目录设备上的二进制动态库(SHARED LIBRARY),而且.so库更安全,不容易被反编译。那么如何打包自己的.so库呢?

一、在Android studio 中配置NDK



在电脑的环境变量中加入NDK的路径


测试


成功!!!OK。

二、新建一个工程,先做一下配置

1、在app的build.gradl下加入

 defaultConfig {
        applicationId "jni.svse.com.jnitest2"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
        ndk{
            moduleName "NDKDEMO"         //生成的so名字
            ldLibs "log", "z", "m"       //链接时使用到的库
            abiFilters "armeabi", "armeabi-v7a", "x86"  //输出指定三种abi体系结构下的so库。目前可有可无
        }
    }
2、在gradle.properties里添加
android.useDeprecatedNdk=true

3、在main下新建一个JNI文件夹


会生成jni文件夹
三、新建调用C/C++的类

public class Load {
    static {
        System.loadLibrary("NDKDEMO");//NDKDEMO可以随便取,但是必须和moduleName "NDKDEMO"  的名字一样
    }
    public  static native  int Add(int a,int b);
}


此时Add会出现红色,不要紧,Alt+Enter,android  studio会在jni下自动帮你生成NDKDEMO.c
#include <jni.h>

JNIEXPORT jint JNICALL
Java_jni_svse_com_jnitest2_Load_Add(JNIEnv *env, jclass type, jint a, jint b) {

    // TODO在这里编写你的逻辑代码,我这里是相加
    return a+b;

}


此时还没有生成.so库

以上2步后会在以下路径生成你的.so库了


生成的类型是根据以下红色来的

ndk{
            moduleName "NDKDEMO"         //生成的so名字
            ldLibs "log", "z", "m"       //链接时使用到的库
            abiFilters "armeabi", "armeabi-v7a", "x86"  //输出指定三种abi体系结构下的so库。目前可有可无
 }


有了自己的.so库怎么使用呢
在新建一个工程,把.so库放到jniLibs下,在工程下新建一个和.so库包名一样的Package,Java_jni_svse_com_jnitest2_Load_Add包名是jni.com.jnitest2,然后再把上面的Load 复制到这里,在Activity里就可以使用了
int value=Load.Add(23, 5);







没有更多推荐了,返回首页