您好,登錄后才能下訂單哦!
Unity3D打包android應用程序時,如果不對DLL加密,很容易被反編譯,導致代碼的泄露。通常的做法是通過加密DLL或者對代碼進行混淆。本文的所要探討的是通過加密的方式來對DLL進行保護,并詳細記錄加密的操作過程。
主要參考
雨松的博文:http://www.xuanyusong.com/archives/3553
http://csftech.logdown.com/posts/452269-android-unity-encryption
這兩篇文章已經詳細介紹了加密的過程,但是還是有些坑和有些操作沒有給出。
原理說明
所有的代碼編譯后是在apk\assets\bin\Data\Managed\Assembly-CSharp.dll下,要做的就是對這個DLL進行加密,Assembly-CSharp.dll由libmono.so加載,所以需要在libmono.so中對加密過的Assembly-CSharp.dll進行解密,幸好unity提供了mono的代碼可以進行編譯修改。當然對于libmono.so也存在被反編譯的風險,本文暫不考慮。
準備
linux系統。本文選擇采用的是Ubuntu14.04,虛擬機也可以,另外可以用Windows + Cygwin進行編譯,不過考慮到這樣做可能踩坑更多,果斷放棄。
unity mono源碼,可以在https://github.com/Unity-Technologies/mono下載,branch選擇unity4.6,直接下zip包,或者git下來都可以,下載下來的zip包為mono-unity-4.6.zip。
unity3d 4.6版本,本文試驗的是4.6的編譯,注意一定要安裝4.6.6+的版本,否則重編的libmono.so會報錯(坑一)。
android ndk, 版本可以根據unity-mono中用的版本來下載,參見unity-mono/external/buildscripts/build_runtime_android.sh, 搜一下ndk=就能找到,本文用到的是r10e,下載下來的ndk為android-ndk-r10e-linux-x86_64.bin。
apktools, 用來對apk進行解包簽名打包,2.0以上版本,否則打包是會報錯。
編譯mono
1)為了方便使用root進行編譯,Ubuntu下root默認不開啟,可以使用:
sudo passwd root
輸兩次密碼后
su -
進行登錄
2)NDK安裝
安裝7z
apt-get install p7zip-full
解壓
7z x android-ndk-r10e-linux-x86.bin
配置環境變量,配置方法有很多,可以修改/etc/profile或者~/.bashrc,這里直接shell下添加臨時的環境變量,不添加后面編mono時會報找不到NDK
export ANDROID_NDK_ROOT=/home/xubo/unity-dev/android-ndk-r10e
export PATH=$ANDROID_NDK_ROOT:$PATH
3)檢查一下mono使用的NDK版本
vi打開mono-unity-4.6/external/buildscripts/build_runtime_android.sh可以找到
perl ${BUILDSCRIPTSDIR}/PrepareAndroidSDK.pl -ndk=r10e -env=envsetup.sh && source envsetup.sh
這里可以確定當前的unity mono使用r10e來進行編譯的
4)安裝編譯必備的一些包
apt-get install autoconf automake bison build-essential gettext git libglib2.0 libtool perl
5)嘗試第一次編譯
./external/buildscripts/build_runtime_android.sh
報錯:
/usr/bin/env: perl -w: No such file or directory
這里unity-mono編譯的時候會去git 一個包android_krait_signal_handler,在external目錄下,就是這個包報錯,這個包出錯的問題很多,是個巨坑(坑二)。
打開android_krait_signal_handler/build.pl,將第一行
#!/usr/bin/env perl -w
改為
#!/usr/bin/perl -w
將下面行
PrepareAndroidSDK::GetAndroidSDK(undef, undef, "r9");
改為實際用到的NDK
PrepareAndroidSDK::GetAndroidSDK(undef, undef, "r10e");
將buildscripts/PrepareAndroidSDK.pm替 換android_krait_signal_handler/PrepareAndroidSDK.pm
打開jni/Application.mk將下兩行都刪掉
APP_PLATFORM := android-9 NDK_TOOLCHAIN_VERSION := clang3.3
否則會報下面的錯誤
make: execvp: /home/xubo/unity-dev/android-ndk-r10e/toolchains/arm-linux-androideabi-4.8: Permission denied
6)嘗試第二次編譯
configure不通過,打開config.log發現
./configure: line 4546: /home/xubo/unity-dev/android-ndk-r10e/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc: No such file or directory
檢查該目錄,發現文件是存在的,這里是因為雖然NDK是64位的,但是交叉編譯工具鏈是32位的,安裝一下,而本文采用的編譯機是64位的,安裝一下64位下運行32位可執行文件的包
apt-get install lib32z1 lib32ncurses5 lib32bz2-1.0
7)嘗試第三次編譯,至此我們應該可以編譯成功了,但還沒涉及到加解密,注意編譯需要在mono的根目錄下進行。最終顯示如下則OK:
Build SUCCESS! Android STATIC/SHARED libraries are found here: builds/embedruntimes/android
加密程序
加密過程可參考上面的鏈接,就是將Assembly-CSharp.dll視作普通的文件,隨便用什么語言寫個加密的代碼,簡單的可以修改幾個字節,做偏移啥的,生成一個新的Assembly-CSharp.dll,替換原來的,這樣一般的破解軟件就沒轍了。
MONO解密
上面只是試驗了一下mono的編譯,關于將解密的代碼添加至mono還沒有做。
打開mono-unity-5.3/mono/metadata/p_w_picpath.c,找到mono_p_w_picpath_open_from_data_with_name函數修改如下
MonoImage * mono_p_w_picpath_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name) { MonoCLIImageInfo *iinfo; MonoImage *p_w_picpath; char *datac; //添加如下代碼 if(name != NULL) { if(strstr(name,"Assembly-CSharp.dll")){ //這里寫下你的解密的代碼,入參data是從Assembly-CSharp.dll讀文件讀出來的 //被加密的原始數據,通過你的解密代碼生成一段新的data } } if (!data || !data_len) { if (status) *status = MONO_IMAGE_IMAGE_INVALID; return NULL; } datac = data; if (need_copy) { datac = g_try_malloc (data_len); if (!datac) { if (status) *status = MONO_IMAGE_ERROR_ERRNO; return NULL; } memcpy (datac, data, data_len); }
MONO正式編譯
正式編譯mono前,還有兩個地方要修改,不修改編譯出來的是debug版本,libmono.so有8M,
打開build_runtime_android.sh, 將下面標紅的-g給去掉,編譯release版本
CFLAGS="\ -DANDROID -DPLATFORM_ANDROID -DLINUX -D__linux__ \ -DHAVE_USR_INCLUDE_MALLOC_H -DPAGE_SIZE=0x1000 \ -D_POSIX_PATH_MAX=256 -DS_IWRITE=S_IWUSR \ -DHAVE_PTHREAD_MUTEX_TIMEDLOCK \ -fpic -g -funwind-tables \
同樣build_runtime_android_x86.sh里面也去掉
Unity3D 簽名
別忘記了,需要unity4.6.6+的版本,本文是在unity4.6.9下測試OK。
制作一個簽名,后面在用apktool重新封包時用得到,用這個簽名對游戲進行build。
Apktool解包封包
1)(windows下操作)確定apktool目錄下有aapt.exe,apktool.bat,apktool.jar,確定版本是2.0+
2)將生成的包例如1.apk 復制到apktool/下
3)cmd命令行下,進入apktool目錄,執行apktool d 1.apk進行解包,會在apktool下生成與包名相同的文件夾1/
4) 將加密過的Assembly-CSharp.dll覆蓋1\assets\bin\Data\Managed\Assembly-CSharp.dll
5) 將編譯過的libmono.so,注意這里選擇armv7a/,和x86/下的,分別覆蓋1\lib\armeabi-v7a和1\lib\x86\下的libmono.so
6) 封包命令行下執行apktool b -f 1,會在1/下生成dist文件,里頭就是新封的包,改名為2.apk,并復制到apktool/下
7)簽名,隱去的是你要填的簽名文件名,和別名
jarsigner -verbose -keystore ****.keystore -signedjar 2_s.apk 2.apk ****
8)2_s.apk就是你加密過的包,進行安裝測試
libmono.so加密
雨松還提到了libmono.so的加密,這里先不涉及吧,strip動態庫,可能能起到相同的效果。
小結
這樣加密經過測試是OK的,可以防止一般的反編譯軟件進行破解了,對于高手可能還防不住,另外編譯mono有點心驚膽戰,android_krait_signal_handler這個工程是個坑,還是有點擔心編出來的libmono.so有咩有啥隱患,所以這樣弄需要在各種android機子上多測試。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。