不少安全專家表示,在互聯網上失去對代碼的控制,就像把銀行的設計圖交給搶劫犯一樣。
Lua是一種被廣泛用于游戲開發中的計算機語言,方便開發者定制自己所需的功能。其中,紅遍全球的《憤怒的小鳥》就是由Lua語言用Wax開發的。此外,夢幻西游、奇跡暖暖、開心消消樂、放置奇兵、最強蝸牛等手游也采用了Lua語言進行編寫。
近年來,Lua腳本在游戲行業長期流行,但Lua腳本泄露事件屢見不鮮,其安全性也引起關注。不法分子通過開私服、開外掛等途徑,實現對游戲代碼的商業變現,這給游戲開發者造成巨大經濟損失,也危及游戲玩家包括賬號、物件在內的虛擬資產安全。
本文將聚焦Lua腳本加密,深入闡述Lua常見的三種加密方式,并探索如何進一步的保護Lua代碼。
一、背景
“Lua”在葡萄牙語中是“月亮”的意思,1993年由巴西的Pontifical Catholic University開發。
作為小巧的解釋性語言,Lua具有簡單、輕量、易維護的特點,且可以根據自身的特性來模擬面向對象,因此其被嵌入到越來越多的應用中,特別是游戲中,為游戲開發帶來了很大的便捷性。例如,Cocos引擎的主流游戲、U3D游戲中的熱更框架xlua都會用到Lua語言。
同時,由于Lua語言自身的這些特性,Lua代碼本身并不安全,很多時候攻擊者可以獲取Lua源碼進行閱讀,分析,盜用以及篡改等,然后進一步的重打包,給游戲本身帶來了很大的安全隱患。
二、Lua現有的保護
對于這種腳本解釋性語言,從代碼保護的角度跟它自身所表現的形式是密不可分的,對于Lua而言,目前市面上手游包中可以看到的主要是lua源碼,luac,luajit三種的表現形式,接下來會詳細的介紹每一種形式以及自身現有的保護以及所暴漏出來的優缺點。
2.1Lua源碼
目前市面上用到Lua源碼本身在游戲中呈現的并不是很多,但是在一些熱更下發中會比較多;因此從源碼保護的思路會很容易的想到針對Lua源碼本身進行混淆保護的方案;目前市面上針對Lua源碼進行混淆的廠家主要有以下這幾家:
XFuscator:
Luraph:
Syanpse Xen:
Ironbrew:
Verdict:
對于這種基于源碼的混淆,優點是是Lua經過處理以后更加的復雜化了,增大了攻擊者進行分析的成本和難度;由于攻防升級,對于上面的混淆也有相對的反混淆處理方式。同時混淆除了自己混淆本身所表現出來的兼容性問題以外,對于開發者也有以下這幾個問題:
1.同一段代碼的混淆在不同時間進行混淆,所得到的混淆效果是不同的:
由于混淆器為了增大混淆的程度和難度,里面會有隨機的代碼要進行熱更,熱更的時候會進行比較,這樣沒辦法進行熱更處理;
2.針對Lua語法混淆的兼容性問題:
由于Lua語法的靈活性,因此去混淆處理的兼容性問題比較多;
3.開發者接入問題:
對于開發者而言進行接入以及出現問題跟第三方進行溝通解決的成本比較大;
2.2luac的形式
luac是作為自己的語言的字節碼格式,與其他腳本語言python等虛擬機中所表現的出來是一樣的,等Lua加載到內存中以后,虛擬機會加載對應的字節碼,由于lua主要有5.1、5.2、5.3三個版本,因此也會有對應的三個格式的luac版本,目前在手游中主流是5.2的版本;
雖然說luac不會以源碼的形式出現,但是由于Lua字節碼的執行以及格式可以根據在Lua源碼中進行探知到,比如luadec反編譯工具,因此luac形式還是不安全的。目前市面上對于這種保護主要有三個形式:
2.2.1:Luac的加密
從Lua的虛擬機源碼處可以得知在luaL_loadbuffer函數會加載Lua,因此有安全意識的廠家會對Lua進行加密。修改這個源碼,在真正的執行前進行解密;
但是由于虛擬機的執行過程是開源的,并且由于cocos工程編譯處理需要靜態鏈接對應的引擎庫,這樣對應的引擎so文件是有符號的,因此對于攻擊者來說,在luaL_loadbuffer函數處可以進行內存的DUMP得到正常的字節碼,然后使用反編譯工具進行處理,進行進一步的修改;
2.2.2:修改Lua虛擬機中opcode的順序
對于Lua這種解釋性語言,無論是虛擬機,還是對應反編譯工具都是有一個固定的opcode的順序,有意識的安全廠商會通過修改對應的opcode的順序進行保護,如下圖所示:左邊是正常opcode的順序,右邊是進行隨機化以后的opcode的;
這樣從新編譯處理完以后的luac可以看到如下圖所示:對應的opcode是不一樣的;
opcode不一樣以及對應的解釋順序是如下:
目前對于這種自定義修改opcode的處理方式,目前攻擊者可以根據通過目標虛擬機加載Lua文件跟正常虛擬機編譯的luac進行對比“吐出”對應的映射表,然后進一步的借助于反編譯工具進行反編譯處理進一步的處理;
或者由于Lua自身的opcode不是很多,如上圖所示可以很輕松的定位到正常的執行順序;因此這種處理方式也不是很安全。
2.2.3:對于Lua的虛擬機執行過程進行保護
可以看到有的游戲廠商對Lua虛擬機進行安全編譯處理,也就是復雜化整個虛擬機的解釋流程,這種做法其實“治標不治本”。
類似如下圖所示:左右是相同功能的一個函數,只是右邊是經過安全編譯器處理的:
對于上面這種處理方式存在的兩個問題:
一是由于Lua本身是開源的,經過安全編譯處理完以后,對應的符號還是存在;攻擊者很容易的定位;
二是對于攻擊者而言其實不用太關心中間的虛擬化解釋執行過程,因此從整個保護的角度來講,實質性作用不大。
2.2.4小結:
目前的以luac為主要表現形式的游戲廠商主要是對于上面三種保護的綜合使用,但是經過分析可以看到從根本上沒有起到一個好的作用,只能阻止部分初級的攻擊者,對于真正的攻擊點的保護沒有抓住。
2.3luajit的形式
由于考慮到Lua的執行效率問題,luajit誕生了,從名字上可以看出,luajit是Lua的即時編譯器生成的,一個用手寫匯編實現的Lua解釋器和一個可以直接生成機器代碼的JIT編譯器;根據dynasm動態生成buildvm_xxx.h的文件,進一步的解釋執行;
目前很多的游戲廠家,為了進一步的保護游戲中的腳本,將Lua處理為luajit的格式,對于luajit而言,也有對應的反編譯工具,ljd或者luajit-lang-toolkit或者luajit-decomp,因此進而一些游戲廠商在經過luajit形式以后會進行加密處理;
借助于cocos自帶的加密,大部分的廠商會通過如下設置自己私有的key和sign值;
以及調用對應的XXTEA的加密算法,可以看到經過加密以后得到如下的luajit的編碼形式:
面對上面這種加密的處理方式,解密也非常的簡單:
一是可以使用HOOK在關鍵的函數處進行內存DUMP;
二是也可以通過反編譯代碼,如下圖所示為某知名游戲對應的key和sign值,然后調用XXTEA進行解密可以得到標準的luajit的形式;然后結合反編譯器進行反編譯修改等等;
三、Lua保護的加強
通過上面對于lua、luac、以及luajit的保護以及逆向的角度來看,要想真正的去保護Lua游戲,可以從以下幾個角度出發:
使用腳本的保護的算法的選擇?
對于虛擬解釋器中的符號怎么進一步的消除掉?
怎么讓開發者盡可能的接入方便?
對于保護的強度上我們應該怎么進一步的考慮?
3.1算法的選擇性
目前很多的游戲廠商通過Quick-Cocos2dx或者cocos自帶的算法,以XXTEA這種為代表進行加密處理,包括對于腳本以及zip包等等加密,這樣使得攻擊者也能夠輕意的去利用這些算法完成解密等操作;因此算法的設計越”私有化“越好,這樣可以在第一個層面上做到防止攻擊者進行靜態的還原腳本。
3.2消除虛擬解釋器中的符號
通過上面可以看到無論是自定義opcode解釋器還是使用安全編譯器處理Lua虛擬機,這其中存在一個問題,由于靜態鏈接的問題,符號表是暴漏的,符號表的存在為攻擊者提供了豐富的分析線索 ,因此可以對Lua的虛擬機解釋引擎進行加殼處理,不僅僅能夠保護上面的私有化解密算法,同時符號的消除使得攻擊者很難得進一步去分析。做到了第二個層面上的保護,同時有了殼以后會對游戲周圍的可疑環境進行檢測,比如上面提到的HOOK等。
3.3讓開發者盡可能的接入方便
比如上面提到的對于Lua在混淆處理的時候,盡可能的考慮到開發者的功能業務,是游戲的邏輯業務還是熱更?否則像上面提到的基于源碼的混淆,每次的隨機化會導致事倍功半。
3.4保護的強度上應該怎么進一步的考慮
從上面的分析過程可以看到這里面我們從以下這幾個角度進行強度上的加強:
在對Lua源碼混淆處理的時候,可以對luac以及luajit對應的反編譯工具進行對坑,由于部分攻擊者不是很懂反編譯的原理,加強使得攻擊者不能反編譯;
由于Lua自身語法的靈活性,可以對于Lua本身的格式進行自定義化,同時修改對應的解釋器部分,這樣攻擊者就不得不分析自定義的格式以及對應的解釋器部分,加大分析的難度。
綜上所述,如下圖所示:
四、總結
在游戲開發領域,Lua與C++、C#的組合帶來了十分強大的功能,但也難免存在被破解的風險。
安全攻擊常常以代碼為目標,達到破解軟件的目的。在導致泄露的網絡安全“短板”中,代碼安全是最本質、最核心的問題。
不可否認的是,在數字經濟時代,對于科技企業而言,代碼既是著作權的一部分,也是核心商業機密之一。核心代碼一旦泄露,導致軟件的核心技術外流,這對于企業幾乎是致命的打擊。
黑客在砸殼、逆向之后,“裸奔”的代碼就面臨全部暴露的風險,增加加密算法十分有必要。