看了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,程序员已经实现了自动加天赋,自动捡东西,自动打怪,自动进入下一层等等