首页 >Unity3D频道 >【Unity3D研究院之游戏开发】 > Unity3D研究院之Android加密DLL与破解DLL .SO(八十一)
2015
07-02

Unity3D研究院之Android加密DLL与破解DLL .SO(八十一)

首先要非常感谢大神提供了这么好的一篇文章,帮助我解决了1年我都没能解决的问题。其次感谢这两天微博好友给我的留言与评论。

阅读本文之前请先阅读大神的这篇。

http://www.luzexi.com/unity3d-%E9%87%8D%E6%96%B0%E7%BC%96%E8%AF%91mono%E5%8A%A0%E5%AF%86dll/

我做的时候有些细节不太一样。一样的地方我就不写了,我把不一样的地方写出来。

加密DLL首先要找准unity版本对应的mono,地址在这里 https://github.com/Unity-Technologies/mono

这里有个很恶心的事情,unity的mono版本并不是按小版本分的,比如我想找unity4.6.1 对应的mono那么它就没有,unity只提供4.3x 或者 4.6x 或者5.1x 这种大版本的mono .从提交时间上来看更新的很随意啊。我感觉要想找到对应的unity版本,可以根据unity这个版本发布的时候,然后在github上找对应时间的mono版本。。

如下图所示,打开网页后,找到对应的branches版本, 这里选择unity-4.6 或者 unity-5.1 这两个版本我已经测试通过。别的版本希望大家都能来参与测试。

Snip20150702_1

 

在说说说恶心的地方,我下载4.6以后,把mono编译出来。放在unity4.6.1的打出来的包里 死活会报错, 但是4.6.6就没问题了。。 不过还好我这里两个项目 一个是用unity4.6.6还有一个是unity5.1.1目前都没出现问题。

下面我都用unity4.6举例,其他版本原理都一样我就不赘述了。

1.github下载下来对应的mono解压放在本地,在终端里先cd到这个目录下。

2.把打包脚本拖入终端中(注意脚本的路径),然后就开始耐心等待吧。估计5分钟左右就OK了。

3.打包脚本分两种, 一个是 arm的,还有一个是x86,执行build_runtime_android.sh 就可以了, 它会自动调用

build_runtime_android_x86.sh。

Snip20150702_2

打包脚本我们需要改一下,因为下载下来的脚本直接运行打的是debug版本,效果就是打出来的.so比unity自带的大很多。我们要改成release版本。

如下图所示,左边是x86,右边是arm。把CFLAGS里的-g改成-O2 (O0 ,O1,O2,OS,O3分了好几个压缩档次,我觉得O2就可以了)然后在LDFLAGS里加上-Wl,–gc-sections 就行了。
Snip20150702_3

注意:今天同事说x86下有些手机进游戏卡死。后来经过一番分析,原来是x86的编译选项和arm不一样。如下图所示,在X86.sh 这里只把-g去掉就行。。别的什么都别改。切记切记!!!

Snip20150830_2

 

然后在下面把这两句代码注释掉,不然编译的时间就要增加了。

#clean_build “$CCFLAGS_ARMv5_CPU” “$LDFLAGS_ARMv5” “$OUTDIR/armv5”
#clean_build “$CCFLAGS_ARMv6_VFP” “$LDFLAGS_ARMv5” “$OUTDIR/armv6_vfp”

在打mono.so前记得改一下解密算法。因为在测试所以解密和加密算法我们就写简单一点。如下图所示,mono/metadata/image.c里面找到 mono_image_open_from_data_width_name 。 因为我只会对自己写的c#编译后的dll加密,所以这里判断一下是否是我们自己的dll,解密算法很简单就是让字节下标为1的字节-1。

如果你要热更DLL时一定要注意!!这里一定要先判断一下name是否为NULL 不然使用System.Reflection.Assembly.Load  在Android平台反射调用DLL的时候unity 会挂的。

	if(name != NULL)
	{
		if(strstr(name,"Assembly-CSharp.dll")){
                       data[0]-=1
		}
	}

 

Snip20150702_4

还有如果想在 mono里打印Log的话可以使用

#include <glib.h>

g_message(“momo: %s”,str);

OK 然后开始编译mono吧。arm 和x86 两个大概 5 分钟左右就能编译完成。对应会会放在mono根目录build的文件夹里。然后回到生成的adnroid工程中,把libmono.so 分别放在x86和armeabi-v7a文件夹下。因为我项目用了slua所以这里也会有一些第三方的.so

Snip20150702_6

再说说自动化的问题,DLL每次代码变更都会重新生成一个新的,那么我总不能每次都手动加密DLL然后在手动的拷贝到assets下面吧。。

再说一句,我的项目在处理自动化打包时用的是adnroid的ant打包。也就是先把unity导出成一个android 工程。然后在打包。所以我的自动化就可以是当android工程生成后,然后把dll读取到内存里,加密后在重新写到原来工程的位置上。如果有朋友不太懂自动化,可以在我博客里搜索一下,以前我有写过。

https://www.xuanyusong.com/archives/3384 环境变量如果你不会加的话,也可以看我这篇文章。

这段代码的意思就是当eclipse的android工程生成后,紧接着就给dll加密。。字节一变那么Dll其实就变成了一个普通的二进制文件。这样用各种反编译Dll的工具就都打不开了。

	//shell脚本来自动调用unity中的这个c#方法
	static void ExportAndroidProject()
	
	{
	
		
		List<string> args = GetArgs("ExportAndroidProject");
	
		
		if (string.IsNullOrEmpty (BuildPipeline.BuildPlayer (GetBuildScenes (), args [0], BuildTarget.Android, BuildOptions.AcceptExternalModificationsToPlayer))) 
		{
			
			encryptDll (args [0]);
		
		}
	
	}
	
	static private void encryptDll(string path)
	
	{
		//DLL在android工程中对应的位置
		
		string inpath = path +"/"+ PlayerSettings.productName +"/assets/bin/Data/Managed/Assembly-CSharp.dll";
		
		if(File.Exists(inpath)){
       		//先读取没有加密的dll
			
       		byte[] bytes = File.ReadAllBytes (inpath);	
			
       		//字节偏移 DLL就加密了。
			bytes [0] += 1;
			//在写到原本的位置上
			
			File.WriteAllBytes (inpath, bytes);
		
		}
	
	}

然后还有前面我们编译出来的两个 mono.so 也要在这里自动化一并拷贝到这个工程对应的目录下面(可以在shell里拷贝,也可以在C#里拷贝)。 接下来就调用自动打包apk就行了。。总之最后的效果就是Dll不能被解开了。如下图所示。

8b0d88d5jw1etl36qex3bj20na0ettbr (1)

8b0d88d5jw1etl36p9o0rj20jp0a70tf (1)

但是,高兴的别太早。DLL是解不开了,但是你的解密算法是写在.so里面的,那么对方反编译你的.so取出解密算法,随便写个小工具就可以把你的DLL逆向回来。。

在windows上下载ida pro 神器(真是道高一尺魔高一丈啊)。

http://www.h4ck.org.cn/2014/08/ida-pro-6-5-with-hex-rays-x86-decompiler-v1-5-and-hex-rays-arm-decompiler-1-7/

然后打开我们编译的libmono.so

找到mono_image_open_from_data_width_name 方法,然后点击F5 解密算法就破解了。(下面我找到了一个避免破解的方法,在本文的最后)

{4A7CD790-4542-4AA0-98DC-F3E0B636762E}

 

怎样才能避免别人这么容易破解你的DLL呢?请看我的下一篇文章 Unity3D研究院之Android二次加密.so二次加密DLL(八十二)

最后编辑:
作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
捐 赠写博客不易,如果您想请我喝一杯星巴克的话?就进来看吧!

Unity3D研究院之Android加密DLL与破解DLL .SO(八十一)》有 125 条评论

  1. 卢栋说:

    通告通告,重要信息gcc: error: unrecognized command line option ‘-V’gcc: fatal error: no input files 对于在编译的时候遇到上面类似的错误问题本人已找到问题。其实大家都关注错问题了,在这个错误的上面还有一个错误就是下面的这句perl -w:No such File or Dictionary这句才是导致编译错误的真正问题,那些说要在linux编译或着是安装什么autoconfig之类库都是没有提到点上。本人在ubuntu和mac系统编译都是遇到同一个问题。所以解决方案就是修改一个脚本就可以了。修改地方如下:1、找到自动下载的文件夹android_krait_signal_handler2、进入build文件夹中打开build.pl3、将第一行#!/usr/bin/env perl -w 修改成 #!/usr/bin/perl -w4、重新编译就可以了。5、祝好运。解决方案主要是google到这个帖子找到的。还有就是谢谢雨松如果还有问题可以发邮件给我。gamelifedong@gmail.com

  2. 雨凇大大,unity美术资源有没有加密措施?

  3. 阿举说:

    留言碰到的问题我发现我都给碰到了,命苦啊,继续学习,谢谢雨松啦。

  4. 阿举说:

    雨松大神,这里 到底应该是 -Wl,杠杠gc-sections 还是杠gc-sections我看你写的是杠,但代码里又是杠杠 ,到底应该哪种?

  5. 说:

    还有这个ida pro具体怎么用?

  6. 说:

    “1.github下载下来对应的mono解压放在本地,在终端里先cd到这个目录下。“终端是什么?CD是什么?

  7. 我是mac 10.10, 一开始brew install autoconf libtool,编译不过。 后来brew install autoconf automake libtool顺利编过了。 缺了automake

  8. 有个疑问,我既然能知道mono加载dll的入口。那在那里替换一个dll不可以吗。这用方式热更新代码不可以吗。这样的话要比lua那些强多了。有什么行不通的地方吗。

  9. 腾讯的游戏 可以 F5 啊。 我以前反编译过。 只是我找不到它解密的密钥而已。。我感觉它的做法和这个类似。。。

  10. 李wan说:

    雨松君。。能告诉下在pc端的编译命令是什么啊。。需要安装什么软件吗

  11. 雪沫泪说:

    libmono编译成功,但却System.load失败,不正确的ELF文件??unity4.6.6==>mono4.6

  12. 刘李明说:

    libmono编译成功,但却System.load失败,不正确的ELF文件??unity4.6.6==>mono4.6

  13. 凯凯哥说:

    GetArgs(“ExportAndroidProject”);?这个函数是哪里的?我怎么找不到

  14. 凯凯哥说:

    GetArgs(“ExportAndroidProject”);
这个函数是哪里的?我怎么找不到

  15. 玄武说:

    报告一个自己踩的弱智坑,那个O2 是大写的o字母,不是0也不是小写o字母。

  16. 浅墨说:

    大神~~ 我照你的步骤编译mono(Unity 5.0), 执行build_runtime_android.sh的时候就报错了,错误提示如下:build_runtime_android.sh: line 14: envsetup.sh: No such file or directoryFailed to locate toolchain/platform; android-ndk-r9 | linux-x86 | arm-linux-androideabi-4.8 | android-9能请教一下要怎么解决吗?

  17. 876249265说:

    雨松大大,win7下怎么编译mono啊,我要打包也是pc端的

  18. 可能是目录有问题。

  19. XUEFEI说:

    Unity3D研究院之Android加密DLL与破解DLL .SO(八十一) - 雨松MOMO程序研究院 - 1 灰常感谢大神,可以加密了。

  20. 猫同人说:

    为什么我点F5只看到下面这些代码呢?int __fastcall start(){ return _cxa_atexit();}

留下一个回复

你的email不会被公开。 必填项已用 * 标注。