看了fatezero的《陰陽師:一個非酋的逆向旅程》後,受益不淺。特別是關於opcode映射關係一節,處理的很精妙。python
對手頭上的遊戲不思議迷宮,技癢的不行。因而上週週六花了整個下午的時間進行了研究。注意本文中針對安卓版本。git
若是讀者也想跟着步驟進行操做,須要準備這些工具:ApkIDE少月版、IDA、python、010editor程序員
APKIDE載入以後,首先看一下lib\armeabi\目錄下,發現了libcocos2dlua.sogithub
從字面意思來看,應該是使用cocos2d引擎,而且使用lua腳本,再看assets\src\算法
發現大量的luac腳本,進一步確認了咱們的想法。010editor打開Main.luac,從頭來看,並不是luac文件的頭app
正常的luaca的頭應該是1B 4C 75 61開頭,以下圖函數
因此不思議迷宮必然是對luac進行了加密。工具
經過IDA打開libcocos2dlua.so,通常狀況下加密會出現cocos2dx_lua_loader->luaL_loadbuffer的某個過程當中測試
源碼以下:ui
而在IDA中,luaL_loadbuffer以前出現了srcDecrypt函數,這但是源碼中沒有出現了。
數據的流向是:從文件讀入->v51->v25->luaL_loadbuffer,再分析srcDecrypt函數
當一個文件的頭爲11 12 13 的時候,就用charMapList進行替換,而charMapList,經過引用查找
又是從buildEncrypyMap中初始化的,顯然這是一組「靜態」的置換表,徹底可逆並且沒有任何難度。
可是回過頭來看apk中的luac文件,沒有一個的文件頭是11 12 13,文件頭所有是applicationWillEnterForeground
並無給咱們帶來任何幫助,只能繼續分析luaLoadBuffer,看到了第二個加密的地方xxtea_decrypt
google,baidu以後,找到很是相似的一段源碼
經過sign對文件進行標記,符合條件用key進行解密,梳理一下luac的總體解密過程
因爲沒有使用srcDecrypt的流程,因此實際上只有xxtea_decrypt,只要找到sign和key,問題就解決了。
經過分析,能夠肯定加密的最終文件格式。文件頭都有固定長度的sign
xxtea_decrypt(buf+decode->m_xxteaSignLen, (xxtea_long)size -(xxtea_long)decode->m_xxteaSignLen, (unsigned char*)decode->m_xxteaKey, (xxtea_long)decode->m_xxteaKeyLen, &len);
再次打開另一個luac文件,兩者相同的文件頭如圖,因此sign爲applicationWillEnterForeground
在IDA中,咱們也找到了這個字符串
查找引用以後,這個字符串在initLuaStack中被調用了。
再經過資料搜索,發現通常使用xxtea算法的,都會使用setXXTEAKeyAndSign來設置sign和key,圖中v3就是setXXTEAKeyAndSign函數
stack->setXXTEAKeyAndSign("123", strlen("123"), "cloud", strlen("cloud"));
那麼天然key就是:applicationDidEnterBackground
首先pip install xxtea-py,安裝python的xxtea的庫
編寫腳本以下:
import xxtea import os sign = 'applicationWillEnterForeground' key = 'applicationDidEnterBackground' def decode(filename): luacdata = open(filename,'rb').read() decrypt_data = xxtea.decrypt(luacdata[len(sign):],key[:16]) open(filename.replace('.luac','.luacx'),'wb').write(decrypt_data)
解密後以下,出現的文件頭爲1B 4C 4A 01,也並不是luac標準頭,難道還有名堂?
通過一番資料查詢以後,這是luajit編譯的bytecode,並不是標準lua。其頭爲1B 4C 4A
在github上找到用於反編譯luajit的項目:https://github.com/NightNord/ljd
因爲該庫只能在python3上跑起來,而我懶得改腳本,因而直接經過命令執行方式,在kali中(同時存在python二、python3)運行了以下腳本
#coding=utf-8 import os sign = 'applicationWillEnterForeground' key = 'applicationDidEnterBackground' path = os.path.join(os.getcwd(),'src') def decode(filename): luacdata = open(filename,'rb').read() decrypt_data = xxtea.decrypt(luacdata[len(sign):],key[:16]) open(filename.replace('.luac','.luacx'),'wb').write(decrypt_data) def decomplie(filename): os.system('python3 ./ljdm/main.py '+filename+' > '+filename.replace('.luacx','.luacxs')) for path,d,filelist in os.walk(path): for filename in filelist: filename = os.path.join(path, filename) if filename.endswith('.luac') and not os.path.isfile(filename.replace('.luac','.luac')): print( filename) decode(filename) if filename.endswith('.luacx') and (not os.path.isfile(filename.replace('.luacx','.luacxs')) or os.path.getsize(filename.replace('.luacx','.luacxs'))==0): print(filename) decomplie(filename)
src目錄對應生成的luacxs就是最終反編譯好的lua源代碼了。
經過大量的分析以後,我發現程序員在代碼中,沒有去掉測試用的上帝模式,只是簡單的隱藏
我在UIAccountBind.luacxs:380行中加入打開上帝模式的一行代碼openGdUI().
這樣當我點擊複製帳號id的時候就會彈出上帝模式窗口
local function onCopyClick(sender, eventType) if eventType == ccui.TouchEventType.ended then copyToClipBoard(rid, getLocStr("text_copied")) end openGdUI() return end
以及GDM.luacxs:24中的check_mode,讓其始終返回爲true,保證上帝模式功能可正常開啓
function check_mode() return true end
而後經過luajit編譯,再進行xxtea加密,打包成APK放入手機。
最終效果圖爲:全自動放置play,程序員已經實現了自動加天賦,自動撿東西,自動打怪,自動進入下一層等等