【Unity】代碼加密(二)dll加密so加密

寫在前面

libmono的編譯方法請參見我的前一篇文章【Unity】代碼加密(一)編譯libmono
如需轉載,請註明出自喵喵丸的博客http://blog.csdn.net/u011643833/article/details/49102423

加密Dll

【這一部分操作我在Windows VS中完成(用的C)】
這個其實可以用任何你熟悉的語言來實現,只要和你的解密方法相對應即可。我所做的流程是這樣的:

  • 讀取從Unity導出Android工程中Assembly-CSharp.dll
  • 讀取的字節流,進行加密(這裏說道的讀取以及下面所述輸出,指的是文件讀寫)
  • 輸出加密後的字節流,生成新的dll,名字依舊是Assembly-CSharp.dll,覆蓋原文件。

(加密後,查看文件內容可發現與未加密之前明顯的不同)

解密Dll

【這一部分操作我在Ubuntu中完成】

  • 從源碼根目錄文件夾下,找到/mono/metadata/image.c這個文件
  • 找到函數mono_image_open_from_data_with_name,這個函數的參數形式是這樣的MonoImage* mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name) 說一下要注意的幾個參數。
  • data 需要加密的字節流
  • data_len data字節流長度
  • need_copy 是否需要深拷貝

  • 代碼形式參考下面(自己添加的部分參照兩段 Add-Addend註釋 之間的代碼)

MonoImage* mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name){
    //..

    //*********************************Add*********************************//
    char *refKey;
    //取得自己解密所需的祕鑰(下方so加密中再進行敘述)
    refKey = getKey();
    //..
    //*******************************Addend*******************************//

    //...
    if (!data || !data_len){
        if(status)
            *status = MONO_IMAGE_IMAGE_INVALID;
        return NULL;
    }

    //*********************************Add*********************************//
    ifstrstr(name, "Assembly-CSharp.dll")){
        char* decodeResult = (char *) malloc (data_len * sizeof(char));
        //..
        //Assembly-CShap.dll字節流(即data)解密(與加密算法對應) 
        //refKey爲祕鑰 將解密結果注入decodeResult中 (這部分就請大家自己填充)
        //..
        memcpy(data, decodeResult, data_len);
        free(decodeResult);
        decodeResult = NULL;

        datac = data;
    }else{
        datac = data;
    }
    //*******************************Addend*******************************//

    //自己修改的代碼一定要放到原文中下面代碼的前面、否則自己解密後的內容會得不到正常的拷貝
    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);
    }

    //..
    //其餘代碼

}
  • 第一段Add-Addend 說明:這部分作用是取到你即將在下面so加密中藏起來的加密祕鑰,在測試時,可以先寫成明文的祕鑰填充refKey,完成so加密後,使用getKey()函數取代。
  • 第二段Add-Addend說明:這部分將參數中傳入的data做解密。調試時,先把這部分代碼正確性做以驗證(反正是C嘛。。在VS裏面寫個命令行。。把加密過的Assembly-CSharp.dll解密後,與未加密前的Assembly-CSharp.dll文件進行文件對比,即可驗證代碼正確性),再放入上面代碼段之中。

加密so

【這一部分操作我在Ubuntu中完成】

爲了解決我們在libmono.so中藏不起來祕鑰的這個問題,在雨鬆Momo大大的博客指導下,已經可以解決啦~
其實解決這個問題的過程雨鬆Momo闡述的已經很明白了,重點的部分在於編譯出encry可執行文件。編譯過程我就不贅述了,只是說一下自己遇到的幾個不太一樣的點

  • 我下載了shelldemo後直接編譯並沒有遇到Momo所遇到的缺少elf.h文件的報錯。正確編譯了(可能和Mono下載到的版本有些出入,但是後續工作完成後發現功能上是沒有問題的)
  • shellAdder1.c中, 存在變量target_section[] = "xxxxxx";,這裏的target_section需要與你寫入image.c中int getKey() __attribute__((section (".xxxxxx")));section字段對應。這篇文章對section的說明比較明確,也是Momo推薦的,我在看的時候其實對0x1、0x2、0x3疑惑了好久,結果發現是標題。。。
  • image.c中解密section的方法寫在哪Momo已經明確的標註了,那麼shellAdder1.c中加密section的方法在哪呢?—–打開shellAdder1.c文件,搜索符號取反’~’(我下載的版本在90行的左右)這裏就是加密方法所在的地方。既然找到了加密解密section的位置,大家自行填充想要的算法即可。
  • 如何快速的驗證加密成功了呢~其一,可以觀察libmono.so文件內容(其實根本不直觀);其二,IDA搜索getKey,沒有加密成功你就可以看到這個函數內容;其三,第一次執行encry libmono.so時,正常執行,第二次執行encry同一文件,報錯爲找不到section字段。證明已經加密過了~

調試以及Tips

這裏是自己覺得有一些助益的小經驗吧

  • 作業的順序,基本和這兩篇博客大標題的順序一致,最好一項一項在工程中驗證,循序漸進。
  • 調試工程,需要有至少一處的交互,或者活動的GameObject,以便觀察。比如說:點擊反饋的事件(不能正常解密的dll 或者so,會顯示第一個靜態的鏡頭,如果沒有一些反饋,比較難驗證你的解密是否真的做成功了)
  • 不要選擇windows來編譯libmono,這個在前一篇有說過,windows用cygwin來做難度和Linux(我沒用Mac實驗)來比,是指數級的。後來Linux成功完成所有工作之後,我又嘗試在windows上面做了一次,還是失敗了。
  • 關於如何將加密的源碼文件加入libmono編譯過程中,這方面其實我很抓瞎的,雖然解決了,但是方法很野蠻。在 mono-unity-x.x/mono/metadata 目錄下有三個makefile文件, 在這三個文件中搜索image關鍵字,在搜索到的位置前面,添加你需要編譯的.h .c文件。這樣就可以在image.c中引用你新添加的文件了。

其實,當時遇到好多想說明的問題,可是如今卻是回憶不起來。暫時只寫到這邊。

如果大家在加密時候遇到了問題,歡迎留言。我會努力解答。

(:з」∠)事實證明,爲了舉一反三 勤快的筆頭子是重要的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章