Hello,我是KitStar。
以下文章整理的不对。还请见谅。
如果您碰到什么其他问题的话,欢迎来 我自己的一个 讨论群`559666429`来,大家一起找答案,共同进步
详细介绍U3D项目加密解密方式。可以保证的说,只要你认真看完。肯定就会成功。(毕竟这是我在坑里滚出来的经验)
对付反编译,比较成熟的方案无非就两种,一种是加密(加壳),一种是混淆(详细链接)。前一种方案,就是对U3D编译出来的dll文件进行二次加密。后一种,就是把程序的可读性,降低到令人发指的程度。当黑客拿到源代码后,也是气血上涌,眼前发黑。好的混淆,需要花极大的精力,才能还原。当他攻破的时候,我们改改程序再混淆,重新发布就又够他折腾的了。 Unity C#代码部分的加密,很多人说混淆,虽然有几个混淆插件CodeGuard、CryptoObfuscator、de4dot...可以用用,但有混淆就有反混淆(de4dot基本都可以搞定),有加壳就有脱壳,有加密就有解密...加密只是提高了门槛提高了难度,而解密只是时间的长短而已。
编译自己的Unity项目,找到 /Data/Managed/Assembly-CSharp.dll ,对它进行加密,可以自己写个小程序,把Assembly-CSharp.dll转换成字节流byte[],然后对byte[]加密。
下面是一些常用的加密(效验)算法:
* 散列:MD5、SHA、SHA3、RIPEMD、Tiger、Whirlpool、CRC32、Adler32
* 对称:Base64、DES、3DES、AES、RC、Rijndael、TripleDES、PBE、3-way、IDEA、MARS、Serpent、 SAFER、 Blowfish、Twofish、Tea、Skipjack、Camellia、Cast、Gost
* 非对称:RSA、Elgamal、Diffie-Hellman、Rabin、ECDsa、Ecc
若对以上算法不了解的可以参看下面两个开源加密类库(谷歌度娘也可以的)
Bouncy Castle(C#和Java版) 代码下载:https://github.com/bcgit/ 官网地址:http://www.bouncycastle.org
Crypto++(C++版) 代码下载:http://sourceforge.net/projects/cryptopp/files/cryptopp/ 官网地址:http://www.cryptopp.com/
安卓端:Unity3D基本客户端的多数代码都会以dll文件形式存下来,功能都在Assembly-CSharp.dll文件中。
当游戏应用被开启时c#vm(也就是mono的虚拟机)会去加载所有dll,从而开始运行真正的程序画面了。而破解的很大一部分都是通过解压apk后拿到主逻辑dll,对dll进行反编译,然后修改后重新编译,再放入apk重新签名打包。所以我们需要针对dll进行加密,以防止他们反编译dll(反编译工具链接:Reflector9VSPro,已经破解)。
加密一个dll文件非常容易,无论你用什么算法都行,但是在哪解密呢?答案是libmono.so。
libmono.so是mono的核心程序,它承载了加载解析dll和虚拟机运行的功能。所以说libmono.so是关键,我们需要修改mono内核程序并重新编译它。
PC端:Pc端与安卓同理,只是不同文件。用于PC加载解析dll和虚拟机运行的文件是在程序打包之后下Mono文件夹的mono.dll文件。所以Pc中mono.dll是关键。我们需要修改mono内核程序并重新编译一个mono.dll. 而在这个dll中将存在这解密Assembly-CSharp.dll文件的代码。
那么下来说到底怎么加密解密喽!!!!!!!!!!
PC端加密解密步骤:
一,加密Assembly-CSharp.dll。
在阅读这篇文章之前,我在处理mono加密问题时,也是参考了雨凇的文章,所以建议先看一下雨凇写的关于加密Dll的文章:
1.Unity3D研究院之Android加密DLL与破解DLL .SO
2.Unity3D研究院之Android二次加密.so二次加密DLL
假装读者已经看过上面的两篇文章了,下面我会记录一下我做的整个加密流程。
一.选取加密Dll的算法
我们主要目的是对程序集:Assembly-CSharp.dll 进行加密,然后修改mono源码,在mono加载Dll的时候进行解密。显然我们需要一种可逆、对称的加密算法,其实这类算法很多,如DES、TEA、XXTEA等,一般这类对称秘钥算法的安全性都是基于秘钥的(Key),所以如何在mono解密是保护自己的秘钥就十分重要了。我目前使用的是XXTEA,实现的话不清楚,但是github上有开源实现,所以直接拿来用了:xxtea-c
1.先用Unity导出一个PC工程,在工程路径 xxxxx\xxxx_Data\Managed\Assembly-CSharp.dll ,这个文件就是需要我们替换的程序集啦.找到之后,等待备用。
2.编写加密Dll工具,大家可以把上面开源xxtea项目中的源码:xxtea.h、xxtea.c 和下面自己要写的的encryptDll.c代码放在同一目录,用MinGW(相关链接)下的gcc编译就可以了:gcc xxtea.c encryptDll.c –o EncryptDll
encryptDll.c代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "xxtea.h"
#define SIZE 1024*1024*10
void main() //命令行参数
{
FILE *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";
char *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);
}
此时,再把你需要加密的Assembly-CSharp文件放到这个文件夹中。最后,直接点击EncryptDll.exe进行对Assembly-CSharp.dll的加密。之后会生成一个加密后的Assembly-CSharp_encrypt.dll文件。此时把这个文件更名为Assembly-CSharp.dll。放回你的原来的打包好的了原文件中,进行替换。
此时,PC端Assembly-CSharp.dll的加密完成。
但是这带来一个问题是,Unity不认加密后的DLL,因为它不再是dll格式了。那我们就需要修改Unity底层代码,好在Unity是基于Mono的,而Mono是开源的。只要找到Mono重新编译个带有解密的mono.dll就可以。那么,下来开始进行mono.dll解密方法植入操作。
二,使用mono.dll进行对Assembly-CSharp.dll的解密。
注意:由于笔者在编译的时候碰到各种坑。最后总结下来最好用VS2010进行编译mono,反正用vs2015是各种坑。
Unity是基于Mono的,地球人都知道...它是开源的 代码下载:https://github.com/Unity-Technologies/mono
直接下Zip包(注意Tag版本与开发用的Unity版本要相同)此处我用的是4.6的版本。
我们下载好了mono包之后。开始用这个包重新编写一个自己的带有解密方法的mono.dll文件。
1,使用上面下载的加密文件xxtea.c和xxtea.h复制到下载的mono的源码里,具体位置在mono/mono/metadata文件夹下。
然后再用vs2010打开mono/msvc/mono.sln,打开之后,通过“解决方案资源管理器”找到libmono项,再将上面的xxtea的两个文件添加到libmono里,并找到libmono下的image.c,添加头文件#include "xxtea.h"和
#include <stddef.h>。
2,再到image.c文件中找一个方法:mono_image_open_from_data_with_name。这个函数就是mono去加载Assembly-CSharp.dll的入口,也就是说我们需要在这里添加我们说需要的解密函数。
第一个方法mono_image_open_from_data_full内实际调用了mono_image_open_from_data_with_name
第二个方法mono_image_open_from_data_with_name的第一个参数char *data这个指针指向运行时Assembly-CSharp.dll的内存地址,
可在该方法内添加或调用对data解密的算法,然后将解密后的data再赋给datac
关于MonoImage这个结构体,它的定义是typedef struct _MonoImage MonoImage; 而_MonoImage这个结构体,它的定义在 /mono/metadata/metadata-internals.h 中
最后就是编译Mono了,编译部分我就不说了自行参看官方说明
该方法虽然是修改Mono内核,偏底层了些,但并不是破解不了,只是要比反混淆的难度高那么一丢丢..
因为这里是针对unity的程序加密,我们完全可以针对单个名称来找到dll。此时在此方法中添加解密代码,如下:
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 (!data || !data_len) {
if (status)
*status = MONO_IMAGE_IMAGE_INVALID;
return NULL;
}
//这是添加的代码,开始 你也可以换成自己想要的解密方法
if (strstr(name, "Assembly-CSharp.dll")) {
char* key = "123456";
size_t len;
char* decryptData = (char *)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;
3,添加完解密方法之后,我们开始编译mono.dll文件。
a、打开Visual Studio Command Prompt(2010)
b、进入mono-unity-4.5\msvc目录
c、执行msbuild.exe mono.sln /p:Configuration=Release_eglib
注意:直接打开mono.sln解决方案,在Visual Studio底下是编译不了的。
我这里用了54秒就编译成功,生成的dll位置在mono\builds\embedruntimes\win64,同时建议在编译的时候,最好将32与64位的dll文件,你后面多半都会使用到的。
最后把你编译出来的mono.dll复制到你打包出来的项目中的Mono文件夹中进行替换。
好了,OK。你可以试试运行游戏,完美运行。再用反编译工具去编译Assembly-CSharp.dll。发现无法编译。
目前测试中:可以成功编译的由,unity-mono-4.6。unity-mono-5.1。unity-mono-5.5.
安卓端加密解密步骤:
请看下一篇更加详细的文章:
Unity3D放破解反编译。DLL加密,mono解密。全程详解。
1,
sudo gedit ~/.bashrc
2.
NDK_ROOT=/home/liaki/NDK/android-ndk-r10e
NDK=$NDK_ROOT
ANDROID_NDK_ROOT=$NDK_ROOT
export NDK_ROOT NDK ANDROID_NDK_ROOT
3,
source ~/.bashrc
source ~/.bashrc
使用APKTool从新打包APK相关命令:
1, apktool d unity5.6.apk
2,apktool b unity5.6 -o newtest.apk
3,jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore likai.keystore -storepass 此处为密码 newtest.apk likai