一、背景
“Unity目前已經全面覆蓋到各個遊戲平臺,超50%的手機遊戲、PC遊戲和主機遊戲基於Unity引擎製作而成,全球月活躍創作者多達150萬,遍佈190多個國家和地區。此外,2019年全球收入前一百的工作室中,有93%的開發者在使用Unity的產品。”
可以看到,Unity作為目前市場的第一大遊戲引擎佔有者,受到越來越多的遊戲開發者和製作者的青睞,同時Unity遊戲會被一些攻擊者和“別有用心”的人盯著,不僅影響到了遊戲市場與遊戲玩家的公平,而且或縮短遊戲自身的生命週期。
本文將重點圍繞“反破解”講述這些安全風險,以及網易易盾團隊如何對unity遊戲進行全方位的矩陣化保護升級。
二、程式碼篡改風險
從上圖可以發現,面對unity的破解問題,遊戲開發商可採取了一個全方位的矩陣化保護方案。方案中首當其衝的是對於程式碼的保護,其中包括指令碼和引擎檔案保護。
2.1 u3d-mono:
透過使用dnSpy.exe對Assembly-CSharp.dll進行反編譯,如下圖所示可以清晰看到其中的邏輯程式碼,以及透過修改IL指令就可以達到進一步的作弊效果。
對於上面這種dll檔案被修改的情況,我們研發了對於dll檔案保護的迭代,如下所示:
2.1.1 整體加密
大部分的加固廠商剛開始都是著手於對於DLL檔案的整體加密,透過閱讀mono的原始碼可知透過修改 mono_image_open_from_data_with_name函式能夠對DLL指令碼進行解密。或者在加固的時對於mono_image_open_from_data_with_name進行HOOK處理;且對於“4D 5A 90”這樣的關鍵魔術字抹掉,防止攻擊者在記憶體中搜尋dump;
但是對於整體加密存在的問題比較容易分析,透過動態除錯或者尋找記憶體中的特徵點進行完整還原。故而對於這種情況,遊戲廠商可以採取“函式加密”方法自保,詳情如下:
2.1.2 函式加密
面對以上整體加密,細緻的“函式加密”不可或缺:在函式執行前進行解密,而不是在記憶體中整體解密,這個時候邊執行邊解密,這時候透過hook mono_image_open_from_data_with_name拿到的dll是不完整的解密,method code還是加密的狀態,這樣大大加強了dll的加密難度,使用dnSpy.exe 和 Reflector.exe 進行反編譯可以看到很多的方法是看不到的,這裡不做展示。
2.1.3 結構自定義
面對上述的函式加密,部分攻擊者透過記憶體定位hook函式,記憶體中去還原dll 的method code,這個時候我們研發了dll的自定義結構,透過對dll的檔案結構進行自定義話,同時配合上面的整體加密和函式加密,最後的效果如下:
對於“結構自定義”的情況,攻擊者需要去分析遊戲的檔案自定義結構,不僅是到記憶體中進行解密,而且得還原我們自己的結構形式。雙重破解“門檻”,使攻擊者的行動難度加深。
2.2 u3d-il2cpp:
隨著MONO Vm在各個平臺的難移植性、MONO版權的受限,以及效能等影響的受限,unity引入了il2cpp機制,加入靜態語言特性把程式碼轉化到native層,雖然在某種程度上提高了遊戲的安全性,但是會把C#中的重要的方法類名等符號資訊儲存在一個叫global-metadata.dat 檔案中,這個時候可以藉助於Il2cppDumper,如下圖所示對一個Demo可以解析到敏感的方法名與類名。對此,遊戲保護依然可以透過分析il2cpp.so得到遊戲的程式碼邏輯。
對於這個情況,我們研發了對global-metadata.dat 的加密方法的迭代:
2.2.1 global-metadata落地加密
第一代是研究了落地加密方式,如下所示為加密前後展示:
這個時候同時對libil2cpp.so檔案進行加固,可以阻擋上面對於符號表的解析以及libil2cpp.so檔案中重要的關鍵欄位的解析,這裡不再展示。
2.2.2 global-metadata記憶體加密
對於第一代的落地加密方式,很容易在執行的時候在本地找到解密的global-metadata.dat檔案,這個時候研發了記憶體加密方法,只是會在記憶體中進行解密,同時抹掉關鍵的標識等,加大分析的難度。
對於上面兩種方式的加密均不需要符號表,方便快捷,一鍵式加密。
2.2.3 global-metadata分塊加密
同時,為了進一步的加強對於global-metadata檔案的保護,我們又研發了分塊加密,只有在函式執行的時候才會進行解密,這個時候在記憶體中拿到的檔案永遠是不完整的,進一步加強對於global-metadata檔案的保護。這樣dump出來再次使用會報錯:
2.2.4 反global-metadata記憶體Dump
在上面靜態加密保護的基礎上,面對一些透過使用在記憶體中反射獲取關鍵資訊的攻擊方式,團隊研究了防動態dump的方法,這樣靜動態的結合極大的加強了對於global-metadata.dat檔案的保護。
2.3 u3d-lua:
Unity自從接入il2cpp以後,透過使用xlua和tolua等進行熱更,這個時候熱更的lua、luac、luajit成為了攻擊者的分析目標。我們提供對於的lua檔案的加密保護以及對應的熱更引擎的保護,防止攻擊者去分析熱更中lua的程式碼邏輯。
2.4 引擎加固:
透過對Assembly-CSharp.dll轉為il2cpp.so結合global-metadata.dat檔案使用IDA分析,可見清晰的邏輯如下:
對於unity引擎中的libil2cpp.so以及自定義的libmono.so檔案,透過獨家研發的引擎檔案進行加固保護,同時對於熱更的lua引擎以及unity引擎進行加固保護,團隊制定了多種的引擎加固方案,“輕量級”與“高強度”並行的加固方案。
三、資源破解分析
3.1AB資源
ab資源作為unity引擎中的核心資源,將所有的資源形式打包成了UnityFS的格式,透過AssetStudio可以對ab資源進行提取,如下圖所示,部分資源的暴露可能帶來資源被竊取、被修改,以及遊戲記憶體在劇透的風險。為了防止對於資源的分析以及複製,遊戲開發商可採取 “ab資源加密”的保護措施。
強度上為邊執行邊解密,同時由於ab資源在一個APP中所佔的體積比較大,儘可能小的降低ab的壓縮率,同時為了考慮到APP執行的效能問題,只會將部分重要的結構資訊進行加密,這個時候可以防止
透過對於ab資源的加密處理,AssetStudio沒辦法對於ab資源進行解析處理,如下圖所示:
3.2靜態資源
在某些特殊情況下,部分unity的包會以靜態資源而不是ab資源的形式存在安裝包中,為了保護自己的美術資源,易盾團隊研發了針對靜態資源的保護,在同樣的強度上邊執行邊解密,同時由於ab資源在一個APP中所佔的體積較大,儘可能小的降低ab的壓縮率,且考慮到APP執行的效能問題,只會加密部分重要的結構資訊,這樣就達到了對應的要求。對於效果同上的ab資源處理,這裡不做具體的效果展示。
四、最後
針對dll檔案、global-metadata檔案、lua檔案、資原始檔,以及引擎檔案的保護,是Unity遊戲安全執行的必經之路。遊戲開發商必須在保障相容性的前提下,根據強度與效能的不同要求進行自動化加固,真正做到遊戲安全的全方位升級。