之前一直和朋友在玩手遊血族。有一天朋友問我能不能把裏面某個角色的立繪拿下來。當時沒多想就答應了,以爲只要解壓找到圖片就行了。但是萬萬沒想到,圖片竟然打不開(被加密了)。
快速分析
下載最新的血族apk並解壓之後看到assets\lua可以猜測這個遊戲是由cocos2d-lua開發的。打開其中的一個lua腳本看到裏面都是亂碼而且開頭也沒有特徵值,應該不是使用xxtea加密的。
story Lua.png
打開png圖片提示無法讀取該文件。
png報錯.png
打開lib\armeabi文件夾,libgame.so是最大的也是等一下分析的重點文件。
libgame.png
快速分析小結
- 血族使用cocos2d-lua開發
- lua腳本和一些重要資源都已經被加密,但不是用官方的xxtea
- 加解密是由libgame.so進行
靜態分析libgame.so
用IDA打開libgame.so,文件較大打開時間比較長。打開字符串窗口可以快速獲得一些重要信息。比如LuaJIT2.0.1、Lua5.1等等。
lua腳本由cocos2dx_lua_loader加載,最後由lua_loadbuffer函數加載到內存中。動態分析一般會在這兩個地方下斷點,然後將lua腳本dump下來。
cocos2dx_lua_loader分析
找到cocos2dx_lua_loader之後f5查看反彙編代碼。根據之後的動態調試分析可以知道,lua腳本是在第一個紅色方框處進行解密操作。
Lua_load.png
lua_load調用了CCFileUtilsAndroid::getFileData,接着調用CCFileUtilsAndroid::doGetFileData,然後調用decryptFile。其實所有的資源都是在decryptFile中進行解密操作。根據文件類型主要分爲三大類:png、jpg、其他加密文件(Lua,csv,xml)。
decryptFile.png
cocos2d::decryptTxt分析
在接下去分析會發現這三個類型的解密過程都是大同小異,先是判斷該文件是否已經加密,如果加密了就調用了cocos2d::decryptData進行真正的解密,只是傳入的參數有所差異。下面用cocos2d::decryptTxt作爲例子
decryptTxt特徵.png
1.判斷文件最後第4個字節到最後第2個字節是否爲0x53 0x44 0x47
2.調用cocos2d::decryptData進行解密操作,傳入的參數只用到了前三個。第一個:開始解密的位置。第二個:需要解密的大小。第三個:用於後續解密的“密鑰”
lua特徵.png
cocos2d::decryptData分析
解密的步驟如下:
1.將需要解密的第一個字節和“密鑰”異或
2.將需要解密的最後一個字節和“密鑰”異或
3.將第一個字節和最後一個字節交換
4."密鑰" =("密鑰"+1)%0xff
...
解密的步驟還是比較簡單的稍微花點時間就能看懂。
decryptData.png
靜態分析小結
函數調用的順序是:
1.cocos2dx_lua_loaderlua腳本加載函數
2.cocos2d::CCFileUtilsAndroid::GetFileData
3.cocos2d::CCFileUtilsAndroid::doGetFileData
4.cocos2d::decryptFile選擇對應的解密函數
5.cocos2d::decryptTxt判斷是否需要解密
6.cocos2d::decryptData解密完成
動態分析
在lua_load和loadbuffer下斷點
lua_load斷點.png
loadbuffer斷點.png
點擊遊戲裏的一些按鈕觸發斷點,當運行到loadbuffer斷點的時候,lua腳本源碼已經出現在內存中了
loadbuffer動態調試.png
- R1:腳本的起始位置
- R2:腳本的長度
可以使用IDC腳本將lua代碼保存到本地
idc腳本.png
效果源碼如下圖
storyLua源碼.png
動態調試總結
在loadbuffer關鍵函數下斷點可直接獲得解密後的代碼
使用IDC腳本將代碼保存下來
優點:省略分析加解密算法的步驟,配合hook框架可以將運行過的代碼都獲取到
缺點:沒運行到的代碼依然得不到
最後放幾張jpg,png解密後的圖片和解密腳本的效果
png解密.png
解密腳本效果.png
詳細代碼已經上傳github