Unity 加密解密

weixin_33860553發表於2015-03-03

解密無非就為了 修改遊戲功能資料、提取遊戲資源、加入自己想加的廣告...
加密就是保護遊戲不被惡意修改,經常看到有人說:"加什麼密,你以為自己寫的程式碼很NB?見不得人?"
我只想說,加密並不是不想讓別人看到我的遊戲邏輯程式碼,而是不想別人去惡意的修改自己做的遊戲罷了...

先說下關於Unity C#程式碼部分的加密(Android和IOS有時間再細說),很多人說混淆,雖然有幾個混淆外掛CodeGuard、CryptoObfuscator、de4dot...可以用用,但有混淆就有反混淆(de4dot基本都可以搞定),有加殼就有脫殼,有加密就有解密...加密只是提高了門檻提高了難度,而解密只是時間的長短而已。
Unity下對C#保護措施並不是很多,加殼就別想了,混淆也有限制,混了和沒混一樣。

除了混淆,我們也可以嘗試其他的保護措施,比如下面的方式:
Unity是基於Mono的,地球人都知道...它是開源的 程式碼下載:https://github.com/Unity-Technologies/mono
直接下Zip包(注意Tag版本與開發用的Unity版本要相同)

編譯自己的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/

有人說.net自帶了安全類庫,確實是在System.Security.Cryptography下有一些常用的演算法,雖然沒有上面的類庫全,但足以平常使用。
其C#原始碼也在Mono開源專案中 位置在 /mcs/class/corlib/System.Security.Cryptography/ 若不想了解加密演算法可乎略,直接引用裡面的方法即可。
如果有閒心的話可以寫一個屬於自己的加密演算法...

此處濾過Hook或是反彙編除錯Mono載入Assembly-CSharp.dll的部分...
接著找到 /mono/metadata/image.c 檢視下面兩個方法
[code]csharpcode:
MonoImage *
mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly)
{
  return mono_image_open_from_data_with_name (data, data_len, need_copy, status, refonly, NULL);
}

MonoImage *
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;
 }
 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);
 }

 image = g_new0 (MonoImage, 1);
 image->raw_data = datac;
 image->raw_data_len = data_len;
 image->raw_data_allocated = need_copy;
 image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
 iinfo = g_new0 (MonoCLIImageInfo, 1);
 image->image_info = iinfo;
 image->ref_only = refonly;
 image->ref_count = 1;

 image = do_mono_image_load (image, status, TRUE, TRUE);
 if (image == NULL)
  return NULL;

 return register_image (image);
}

第一個方法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核心,偏底層了些,但並不是破解不了,只是要比反混淆的難度高那麼一丟丟..

相關文章