Unity3D-重新編譯Mono加密DLL

Unity3D-重新編譯Mono加密DLL。安卓應(yīng)用總是讓人頭疼,游戲遭到破解與反編譯是研發(fā)的人最不愿意看到的。自己的辛苦勞動(dòng)成果被人隨意竊取與利用,對(duì)這些咬牙切齒的痛恨。所以我們需要加強(qiáng)自身的反破解技術(shù)力量。不過這世上沒有破解不了的東西,道高一尺魔高一丈,我們做的只是讓破解更加困難而已。讓那些破解的人付出點(diǎn)代價(jià)才能得到他們想要的,如果他們覺得代價(jià)太高,看不清前面的道路,他們就有可能放棄,然后我們的目的達(dá)到了。
游戲本身加密方式有很多,對(duì)apk加殼,防止apk二次打包等。對(duì)這些android的加密與破解技術(shù)看過比較好的文章參考:
《Android安全及病毒分析》 ,其中《Android APK加殼技術(shù)方案【2】》 最為經(jīng)典。而本篇文章我們主要來說說針對(duì)Unity3D的加密。
閑扯就到這里,我們開始說正事:
Unity3D所有客戶端的代碼都會(huì)以dll文件形式存下來,當(dāng)游戲應(yīng)用被開啟時(shí)c#vm(也就是mono的虛擬機(jī))會(huì)去加載所有dll,從而開始運(yùn)行真正的程序畫面了。而破解的很大一部分都是通過解壓apk后拿到主邏輯dll,對(duì)dll進(jìn)行反編譯,然后修改后重新編譯,再放入apk重新簽名打包。所以我們需要針對(duì)dll進(jìn)行加密,以防止他們反編譯dll。
加密一個(gè)dll文件非常容易,無論你用什么算法都行,但是在哪解密呢?答案是libmono.so。libmono.so是mono的核心程序,它承載了加載解析dll和虛擬機(jī)運(yùn)行的功能。所以說libmono.so是關(guān)鍵,我們需要修改mono內(nèi)核程序并重新編譯它。
下面將開始mono的編譯過程,別看步驟寫得簡(jiǎn)單明了,其實(shí)我花了起碼一個(gè)多星期的思考,嘗試,失敗,再思考,再嘗試,再失敗.....總結(jié)其中原因一方面也是自己的愚鈍的資質(zhì),另一方面是unity mono和mono并不一樣,unity mono缺少編譯文檔并且還混合著原mono的編譯文檔,導(dǎo)致誤判了很多:
1.首先不要認(rèn)為unity mono 與 原生態(tài)mono一樣??梢跃幾gmono就可以同樣步驟編譯unity mono。我在這里嘗試了很久,使用configure進(jìn)行編譯,嘗試使用不同的編譯參數(shù),進(jìn)行編譯,最后發(fā)現(xiàn)unity mono使用的是ndk-9下的linux-4.8編譯器,所有參數(shù)都是根據(jù)這個(gè)編譯器所設(shè)定的。
2.unity mono 地址:https://github.com/Unity-Technologies/mono 你需要從這里下載unity mono。
3.mono需要autoconf automake libtool pkg-config這些工具。你最好還是去下載安裝了。你可以用brew安裝。brew install autoconf automake libtool pkg-config。

4.我一開始使用mac x8664進(jìn)行編譯,折騰了很久然后建了個(gè)linux-x8664虛擬機(jī)來編譯,然后又折騰了很久,又建了個(gè)linux-i386來重新編譯mono,因?yàn)槲乙恢闭J(rèn)為交叉編譯需要加些不同的編譯參數(shù)和變量。在linux-i386首次編譯成功后又開始轉(zhuǎn)化到mac上,進(jìn)行交叉編譯也一樣成功,最后發(fā)現(xiàn)其實(shí)是我沒找對(duì)路子。這路子就是unity 的mono-build-tool:https://github.com/Unity-Technologies/monobuildtools 它已經(jīng)在unity mono的項(xiàng)目里了,在mono的external/buildscripts下。
5.buildscripts下的buildruntimeandroid.sh是編譯安卓平臺(tái)的關(guān)鍵。它是unity制作的一個(gè)自動(dòng)編譯 mono 流程的腳本。你需要將這個(gè)腳本copy到mono根目錄下再執(zhí)行。
6.腳本里寫些內(nèi)容,如果你懶得看,我?guī)湍闵晕⒔忉屜?。它?huì)去檢查你當(dāng)前的ANDROIDNDKROOT環(huán)境變量是否是指向ndk-9,所以你需要去下ndk-9版本,放到機(jī)子上,然后編輯環(huán)境變量ANDROIDNDKROOT指向它,如果你沒有它會(huì)通過perl模塊lwp-download去下載ndk-9,但是你必須要要有這個(gè)perl模塊才行,我勸你還是老老實(shí)實(shí)自己去下吧。ndk版本下載地址參考這里:《android-sdk-ndk-studio-下載列表和構(gòu)建說明》。如果是linux下編譯環(huán)境變量設(shè)定參考這里:《linux環(huán)境變量簡(jiǎn)介》。然后呢,它會(huì)用git去clone一個(gè)編譯時(shí)用到的庫(kù),這個(gè)也是unity自己改編過的一個(gè)庫(kù),地址為:https://github.com/Unity-Technologies/krait-signal-handler ,這個(gè)庫(kù)有個(gè)坑說下:perl腳本build.pl頭部有個(gè)命令是#!/usr/bin/env perl -w,這個(gè)在部分機(jī)子上并不兼容,如果你有錯(cuò)誤停在這里這個(gè)文件上,你可以將env去除再嘗試手動(dòng)perl build.pl 運(yùn)行構(gòu)建一遍沒問題再重新編譯,原因參考:http://abloz.com/2011/01/13/why-use-usr-bin-env.html 。最后就先make clean && make distclean 清除前面編譯的內(nèi)容,然后進(jìn)行預(yù)編譯configure,參數(shù)都在腳本里設(shè)置好了,你不需要關(guān)心了。預(yù)編譯后就開始make編譯了。
7.執(zhí)行buildruntimeandroid.sh后terminal基本都是刷屏的節(jié)奏。刷刷刷的編譯輸出,你根本來不及看清到底做到哪了做了些什么內(nèi)容。而config.log這個(gè)文件記錄所有的編譯輸出,包括哪行錯(cuò)誤了,哪行通過了。調(diào)試基本也考這個(gè)log文件,如果關(guān)鍵部位錯(cuò)誤它會(huì)停止,然后你就可以針對(duì)性的查了。這里提醒一點(diǎn),編譯時(shí)它很多地方都是在檢測(cè)編譯器是否正常,因?yàn)樗_認(rèn)編譯器對(duì)錯(cuò)誤的編譯內(nèi)容是否能夠檢測(cè)到,所以很多錯(cuò)誤內(nèi)容只是測(cè)試內(nèi)容-你需要省略掉。
8.如果編譯成功,那就恭喜你了。windows下我沒有測(cè)試過,有可能會(huì)增加不少坑,我建議還是用linux或者mac編譯吧,因?yàn)槲宜鸭Y料的時(shí)候不少人對(duì)windows下編譯mono都抱怨不少。那么我們開始邁入下一個(gè)坑吧:)
下面介紹加解密DLL部分:
加密算法自己選我不多說了,但我這里要引用一篇同樣介紹mono的dll加密的文章,我覺得也寫得滿不錯(cuò)的,但是文章描述不夠詳盡。我這篇文章彌補(bǔ)了他的不足,將細(xì)節(jié)補(bǔ)充得更加細(xì)致。你大可以兩篇文章加起來參考。http://www.unitymanual.com/home.php?mod=space&uid=7672&do=blog&id=1440 不知道地址是不是原作者的,如果不是我再更換吧。

1.首先找到dll解密入口。mono下/mono/metadata/image.c里monoimageopenfromdatawithname是關(guān)鍵方法,參數(shù)中的data是dll傳入的數(shù)據(jù)。你要做的就是將它解密后傳給datac,這個(gè)方法程序你必須看下,因?yàn)槟阋私庀陆饷艹绦蚍旁谀牟藕线m。
2.大部分dll都會(huì)通過monoimageopenfromdatawithname這個(gè)方法進(jìn)行加載,但不是所有dll,例如mscorlib.dll和System.Core.dll就不會(huì),可能還有其他dll,我并不確定還有哪些。所以你還是得辨別下哪些dll會(huì)通過這個(gè)方法,這樣你才能確定哪個(gè)dll可以加密。如何判斷data屬于哪個(gè)dll呢,參數(shù)name就是data的路徑名,name打印出來后就像:/data/app/com.xx.xx.apk/assets/bin/Data/Managed/xxx.dll 這樣。
3.打印調(diào)試。你可以使用gmessage例如:gwarning("dll name: %s \n", name); 其他的打印調(diào)試你可以查看源碼中的它寫的代碼。很容易找到,查關(guān)鍵字LOG吧。
4.改完后重新編譯mono,找到libmono.so(find . -name libmono.so),完成編譯后libmono.so的平臺(tái)有好幾個(gè),你可以根據(jù)自己的平臺(tái)來選。有人拷貝這些mono重新編譯過的文件去覆蓋了unity編輯器的原來mono文件,這樣也可行。但我選擇在打包android時(shí)再?gòu)耐獠繌?fù)制libmono.so,這樣就可以繞過編譯器重新編譯后無法讀取無加密dll的麻煩,可以少做一層無意義的編輯器狀態(tài)下的加解密工作。
5.mono解密部分就到這里了。其他部分的關(guān)鍵就是你的加解密程序了,是否能夠加密和解密都是ok的并且都是不改變size。你需要的參數(shù)有data和datalen,monoimageopenfromdatawith_name方法里面都有。
6.為了安全起見我使用c來編寫加密程序,因?yàn)槲艺J(rèn)為c#和c的編譯器對(duì)于變量?jī)?nèi)存的存儲(chǔ)機(jī)制不一樣,怕引起不必要的麻煩。 這里要非常感謝一個(gè)人,全程都在提供幫助:熾樂@宗樹
轉(zhuǎn)載請(qǐng)注明出處:http://www.luzexi.com

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容