浅析android手游lua脚本的加密与解密
2018.05.02更新
? ? ? ? 這段時(shí)間在翻備份的硬盤(pán),突然發(fā)現(xiàn)了以前的分析項(xiàng)目和代碼,從里面提取了之前附件的內(nèi)容,現(xiàn)在上傳給大家,真是柳暗花明又一村啊。附件包括201703版本的夢(mèng)幻手游里面提取的so文件和一些加密后的資源文件(包括lua腳本),并包括了2個(gè)撲魚(yú)APK文件,最后還打包了解密代碼,供大家參考。
? ? ? ? 附件太大,快100MB,上傳不來(lái)論壇,我又放到百度網(wǎng)盤(pán)了......
? ? ? ? 鏈接:https://pan.baidu.com/s/1DVgH0qHYPkiHBIiV2UsU7g 密碼:ipt3
?
2018.04.09更新
附件是真的找不到了, 大家主要理解思路吧。百度網(wǎng)盤(pán)的附件好多朋友都下載和保存過(guò),能不能發(fā)一份到論壇上傳?感謝感謝~
?
2017.04.15更新
1. 在編輯過(guò)程中,5.1后半段內(nèi)容(解密和反編譯部分)被刪除了,現(xiàn)在補(bǔ)上。
2. 在3.3里說(shuō)到,“修改lua項(xiàng)目中的opcode后,編譯生成lua.exe再替換到反編譯目錄下,就可以反編譯”,這一句是錯(cuò)誤的,正確是“修改lua項(xiàng)目中的opcode后,重新編譯反編譯工具luadec51項(xiàng)目,就可以反編譯了”,已經(jīng)修改。
?
0.前言
這篇文章是本人在學(xué)習(xí)android手游安全時(shí)總結(jié)的一篇關(guān)于lua的文章,不足之處歡迎指正,也歡迎大牛前來(lái)交流。本文目錄如下: 目錄 0. 前言 1. lua腳本在手游中的現(xiàn)狀 2. lua、luac、luaJIT三種文件的關(guān)系 3. lua腳本的保護(hù) 3.1 普通的對(duì)稱加密,在加載腳本之前解密 3.2 將lua腳本編譯成luaJIT字節(jié)碼并且加密打包 3.3 修改lua虛擬機(jī)中opcode的順序 4. 獲取lua代碼的一般方法 4.1 靜態(tài)分析so解密方法 4.2 動(dòng)態(tài)調(diào)試:ida + idc + dump 4.3 hook so 4.4 分析lua虛擬機(jī)的opcode的順序 5. 三個(gè)游戲的lua腳本解密過(guò)程 5.1 54捕魚(yú) 5.2 捕魚(yú)達(dá)人4 5.3 夢(mèng)幻西游手游 6. 總結(jié) 參考文章主要用到的工具和環(huán)境:
1 win7系統(tǒng)一枚 2 quick-cocos2d-x的開(kāi)發(fā)環(huán)境(弄一個(gè)開(kāi)發(fā)環(huán)境方便學(xué)習(xí),而且大部分lua手游都是用的cocos2d-x框架,還有一個(gè)好處,可以查看源碼關(guān)鍵函數(shù)中的特征字符串,然后在IDA定位到關(guān)鍵函數(shù),非常方便) 3 IDA6.8(分析so文件+動(dòng)態(tài)調(diào)試so) 4 vs2015(編寫(xiě)解密代碼)這里建議用vs2013來(lái)編譯運(yùn)行cocos2d-x,vs2015太多坑要填了..... 5 AndroidKiller 1.3.1(反編譯apk,其中apktool.exe是最新版) 6 luadec51(反編譯luac) 7 luajit-decomp(反編譯luaJIT) 等等... 1.lua腳本在手游中的現(xiàn)狀 略。 2.lua、luac、luaJIT三種文件的關(guān)系?????在學(xué)習(xí)lua手游過(guò)程中,本人遇到的lua文件大部分是這3種。其中l(wèi)ua是明文代碼,直接用記事本就能打開(kāi),luac是lua編譯后的字節(jié)碼,文件頭為0x1B 0x4C 0x75 0x61 0x51,lua虛擬機(jī)能夠直接解析lua和luac腳本文件,而luaJIT是另一個(gè)lua的實(shí)現(xiàn)版本(不是原作者寫(xiě)的),JIT是指Just-In-Time(即時(shí)解析運(yùn)行),luaJIT相比lua和luac更加高效,文件頭是0x1B 0x4C 0x4A。
?
luac:????
?
? ? ?luajit:
? ? ? 3.lua腳本的保護(hù)?????一般有安全意識(shí)的游戲廠商都不會(huì)直接把lua源碼腳本打包到APK中發(fā)布,所以一般對(duì)lua腳本的保護(hù)有下面3種:
?
3.1 普通的對(duì)稱加密,在加載腳本之前解密? ? ?這種情況是指打包在APK中的lua代碼是加密過(guò)的,程序在加載lua腳本時(shí)解密(關(guān)鍵函數(shù)luaL_loadbuffer ),解密后就能夠獲取lua源碼。如果解密后獲取的是luac字節(jié)碼的話,也可以通過(guò)反編譯得到lua源碼,反編譯主要用的工具有unluac和luadec51,后面會(huì)具體分析。
?
3.2 將lua腳本編譯成luaJIT字節(jié)碼并且加密打包? ?? 因?yàn)榉淳幾g的結(jié)果并不容易查看,所以這種情況能夠較好的保護(hù)lua源碼。這個(gè)情況主要是先解密后反編譯,反編譯主要是通過(guò)luajit-decomp項(xiàng)目,它能夠?qū)uajit字節(jié)碼反編譯成偽lua代碼。
?
3.3 修改lua虛擬機(jī)中opcode的順序? ? ?這種情況主要是修改lua虛擬機(jī)源碼,再通過(guò)修改過(guò)的虛擬機(jī)將lua腳本編譯成luac字節(jié)碼,達(dá)到保護(hù)的目的。這種情況如果直接用上面的反編譯工具是不能將luac反編譯的,需要在程序中分析出相對(duì)應(yīng)的opcode,然后修改lua項(xiàng)目的opcode的順序并重新編譯生成反編譯工具,就能反編譯了,后面會(huì)具體分析。 ? ??
?
?????一般上面的情況都會(huì)交叉遇到。
?
4.獲取lua源碼的一般方法?????這里主要介紹4種方法,都會(huì)在第5節(jié)中用實(shí)例說(shuō)明。
?
4.1 靜態(tài)分析so解密方法? ? ?這種方法需要把解密的過(guò)程全部分析出來(lái),比較費(fèi)時(shí)費(fèi)力,主要是通過(guò)ida定位到luaL_loadbuffer函數(shù),然后往上回溯,分析出解密的過(guò)程。
?
4.2 動(dòng)態(tài)調(diào)試:ida + idc + dump? ? ?這里主要通過(guò)ida動(dòng)態(tài)調(diào)試so文件,然后是定位到luaL_loadbuffer地址,游戲會(huì)在啟動(dòng)的時(shí)候通過(guò)調(diào)用luaL_loadbuffer函數(shù)加載必要的lua腳本,通過(guò)在luaL_loadbuffer下斷點(diǎn) ,斷下后就可以運(yùn)行idc腳本將lua代碼導(dǎo)出(程序調(diào)用一次luaL_loadbuffer加載一個(gè)lua腳本,不寫(xiě)idc腳本的話需要手動(dòng)導(dǎo)N多遍.....)。
?
4.3 hook so? ? ?跟4.2原理一樣,就是通過(guò)hook函數(shù)luaL_loadbuffer地址,將代碼保存,相比4.2的好處是有些lua腳本需要在玩游戲的過(guò)程中才加載,如果用了4.2的方法,游戲過(guò)程中 中斷一次就需要手動(dòng)運(yùn)行一次idc腳本,而且往往每次只加載一個(gè)lua文件,如果是hook的話,就不需要那么麻煩,直接玩一遍游戲,全部lua腳本就已經(jīng)保存好了。
?
4.4 分析lua虛擬機(jī)的opcode的順序? ? ?這里主要是opcode的順序被修改了,需要用ida定位到虛擬機(jī)執(zhí)行l(wèi)uac字節(jié)碼的地方,然后對(duì)比原來(lái)lua虛擬機(jī)的執(zhí)行過(guò)程,獲取修改后的opcode順序,最后還原lua腳本。
?
5.三個(gè)游戲的lua腳本解密實(shí)例?????好了,下面用3個(gè)例子來(lái)說(shuō)明上面的情況。
?
5.1 54捕魚(yú) 首先用AndroidKiller 加載,然后查看lib目錄下的so文件,發(fā)現(xiàn)libcocos2dlua.so文件,基本可以確定是lua腳本編寫(xiě)的了。這里有個(gè)小技巧,當(dāng)有很多so文件的時(shí)候,一般最大的文件是我們的目標(biāo)(文件大是因?yàn)榧闪薼ua引擎)。既然有l(wèi)ua引擎,肯定有l(wèi)ua腳本了,接著找lua腳本。資源文件和lua腳本文件都是在assets目錄下。發(fā)現(xiàn)游戲的資源文件和配置文件都是明文,這里直接修改游戲的配置文件就可以作弊(比如修改升級(jí)炮臺(tái)所需的金幣和鉆石,就可以達(dá)到快速升級(jí)炮臺(tái)的目的),然后并沒(méi)有發(fā)現(xiàn)類似lua腳本的文件。 順手解壓了一下res目錄下的liveupdate_precompiled.zip,發(fā)現(xiàn)解壓失敗,看來(lái)是加密了(看名字就知道是更新游戲的代碼)這里說(shuō)明一下,一般遇到xxxx_precompiled.zip的這種文件,都是quick-cocos2d-x框架(quick簡(jiǎn)單來(lái)說(shuō)就是對(duì)lua的拓展實(shí)現(xiàn)),在quick-cocos2d-x框架下可以用compile_scripts命令將lua文件加密打包成xxxx_precompiled.zip,游戲運(yùn)行時(shí)再解密加載。注意,這種方式打包的lua腳本一般都會(huì)被編譯成luaJIT,加載的關(guān)鍵函數(shù)是loadChunksFromZIP,可以在IDA中直接搜索該函數(shù),如果找不到可以搜索字符串luaLoadChunksFromZIP來(lái)定位到函數(shù) OK,了解了原理接下來(lái)開(kāi)始動(dòng)手分析,將libcocos2dlua.so拖到IDA中加載,函數(shù)中直接搜索loadChunksFromZIP,定位后F5。????
? ? ?一直向上回溯(交叉引用 ),來(lái)到下圖,發(fā)現(xiàn)解密的密鑰和簽名,其中xiaoxian為密鑰,XXFISH為簽名
? ??
進(jìn)去函數(shù)里面看看,其實(shí)會(huì)發(fā)現(xiàn)調(diào)用了XXTea算法,這里我們也可以直接分析loadChunksFromZIP函數(shù)的源碼(所以配置一個(gè)cocos2d的開(kāi)發(fā)環(huán)境還是非常有必要的)。查看源碼里的lua_loadChunksFromZIP函數(shù)的原型: int CCLuaStack::lua_loadChunksFromZIP(lua_State *L) {if (lua_gettop(L) < 1){ // 這里可以發(fā)現(xiàn)用字符串也可以定位到目標(biāo)函數(shù)CCLOG("lua_loadChunksFromZIP() - invalid arguments");return 0;} ...if (isXXTEA){// decrypt XXTEA// 這里調(diào)用了解密函數(shù)xxtea_long len = 0;buffer = xxtea_decrypt(zipFileData + stack->m_xxteaSignLen,(xxtea_long)size - (xxtea_long)stack->m_xxteaSignLen,(unsigned char*)stack->m_xxteaKey,(xxtea_long)stack->m_xxteaKeyLen,&len);delete []zipFileData;zipFileData = NULL;zip = CCZipFile::createWithBuffer(buffer, len);} ... }? ?
接下來(lái)直接寫(xiě)解密函數(shù)(在cocos2d-x項(xiàng)目里面寫(xiě)的解密函數(shù),很多工具直接可以調(diào)用)
void decryptZipFile_54BY(string strZipFilePath) {CCFileUtils *utils = CCFileUtils::sharedFileUtils();unsigned long lZipFileSize = 0;unsigned char *szBuffer = NULL;unsigned char *zipFileData = utils->getFileData(strZipFilePath.c_str(), "rb", &lZipFileSize);xxtea_long xxBufferLen = 0;szBuffer = xxtea_decrypt(zipFileData + 6, //6為簽名XXFISH的長(zhǎng)度(xxtea_long)lZipFileSize - (xxtea_long)6, //減去簽名的長(zhǎng)度(unsigned char*)"xiaoxian", //xiaoxian為密鑰(xxtea_long)8, //密鑰的長(zhǎng)度&xxBufferLen);//獲取zip里面的所有文件CCZipFile *zipFile = CCZipFile::createWithBuffer(szBuffer, xxBufferLen);int count = 0;string strFileName = zipFile->getFirstFilename();while (strFileName.length()){cout << "filename:" << strFileName << endl;unsigned long lFileBufferSize = 0;unsigned char *szFileBuffer = zipFile->getFileData(strFileName.c_str(), &lFileBufferSize);if (lFileBufferSize){++count;ofstream ffout(strFileName, ios::binary);ffout.write((char *)szFileBuffer, sizeof(char) * (lFileBufferSize));ffout.close();delete[] szFileBuffer;}strFileName = zipFile->getNextFilename();}delete[] zipFileData; }?
? ? 解密后的文件如下:? ??
這幾個(gè)都是更新游戲的代碼,是luajit的文件,所以接下來(lái)需要反編譯。IDA中查看下lua版本和luajit版本,字符串分別搜索lua+空格和luajit+空格:?
????lua版本為5.1
?
? ? luajit版本為2.1.0
?
? ? 反編譯本人用到的是luajit-decomp,這里需要注意,luajit-decomp默認(rèn)的lua版本為5.1,luajit版本為2.0.2,我們需要下載對(duì)應(yīng)lua和luajit的版本,編譯后替換luajit-decomp下的lua51.dll、luajit.exe、jit文件夾。反編譯時(shí)需要注意的文件和文件夾:
? ??
? ? 這里需要下載版本為2.1.0-beta2的luajit,并且編譯生成文件后,復(fù)制LuaJIT-2.1.0-beta2\src路徑下的lua51.dll、luajit.exe文件和jit文件夾覆蓋到luajit-decomp目錄中。luajit-decomp用的是autolt3語(yǔ)言,原腳本默認(rèn)是只反編譯當(dāng)前目錄下的test.lua文件,所以需要改一下decoder.au3文件的代碼。修改后的代碼另存為jitdecomp.au3文件,編譯后為jitdecomp.exe。并且增加了data目錄,目錄下有3個(gè)文件夾,分別為:
luajit:待反編譯的luajit文件 asm:反匯編后的中間結(jié)果 out:反編譯后的結(jié)果?
?????將解密后的文件放到luajit文件夾,運(yùn)行 jitdecomp.exe,反編譯的結(jié)果在out目錄下,結(jié)果如下:
這個(gè)反編譯工具寫(xiě)得并不好,反編譯后的文件閱讀起來(lái)挺困難的,而且反編譯的lua格式有問(wèn)題,所以不能用lua編輯器格式化代碼。?
5.2 捕魚(yú)達(dá)人4
這個(gè)游戲主要是用ida動(dòng)態(tài)調(diào)試so文件,然后用idc腳本把lua文件全部dump下來(lái)的方法。首先用AndroidKiller加載apk,在lib目錄下有3個(gè)文件夾,不同的手機(jī)cpu型號(hào)對(duì)應(yīng)不同的文件夾 。本人的手機(jī)加載的目標(biāo)so文件在armeabi-v7a文件下:?
? ? ?接著,ida加載libcocos2dlua.so文件,定位到函數(shù)luaL_loadbuffer,可以在函數(shù)中直接搜索,也可以字符串搜索"[LUA ERROR]"來(lái)定位到函數(shù)中,函數(shù)分析如下:
LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size,const char *name)?
?????所以在ARM匯編中,參數(shù)R0為lua_State指針,參數(shù)R1為腳本內(nèi)容,R2為腳本大小,R3為腳本的名稱,寫(xiě)一段IDC腳本dump數(shù)據(jù)即可:
#include <idc.idc> static main() {auto code, bp_addrese,fp,strPath,strFileName;bp_addrese = 0x7573022C; // luaL_loadbuffer函數(shù)地址 ,靜態(tài)分析獲取的函數(shù)地址+so文件的地址得到AddBpt(bp_addrese); // 下斷點(diǎn),也可以手動(dòng)下斷while(1){code = GetDebuggerEvent(WFNE_SUSP|WFNE_CONT, 15); // 等待斷點(diǎn)發(fā)生,等待時(shí)間為15秒if ( code <= 0 ){Warning("錯(cuò)誤代碼:%d",code);return 0;}Message ("地址:%a, 事件id:%x\n", GetEventEa(), GetEventId()); // 斷點(diǎn)發(fā)生,打印消息strFileName = GetString(GetRegValue("R3"),-1,0); // 獲取文件路徑名strFileName = substr(strFileName,strrstr(strFileName,"/")+1,-1); // 獲取最后一個(gè)‘/’后面的名字(文件的名字)去掉路徑strPath = sprintf("c:\\lua\\%s",strFileName); // 保存lua的本地路徑fp = fopen(strPath,"wb");savefile(fp,0,GetRegValue("R1"),GetRegValue("R2"));fclose(fp);Message("保存文件成功: %s\n",strPath);} } //字符串查找函數(shù),從后面向前查找,返回第一次查找的字符串下標(biāo) static strrstr(str,substr1) {auto i,index;index = -1;while (1){i = strstr(str,substr1);if (-1 == i) return index;str = substr(str,i+1,-1);index = index+i+1;}; }?
? ? ?ida動(dòng)態(tài)調(diào)試so文件網(wǎng)上有很多文章,這里就不詳細(xì)說(shuō)明了。通過(guò)idc腳本獲取的部分?jǐn)?shù)據(jù)如下:?
雖然文件的后綴名是.luac,但其實(shí)都是明文的lua腳本。?
5.3.夢(mèng)幻西游手游
AndroidKiller反編譯apk,查看lib下存在libcocos2dlua.so,基本上確定是lua寫(xiě)的:?
在assets\HashRes目錄下,存在很多被加密的文件,這里存放的是lua腳本和游戲的其他資源文件?
接著找lua腳本的解密過(guò)程,用ida加載libcocos2dlua.so文件,搜索luaL_loadbuffer函數(shù),定位到關(guān)鍵位置,這里就是解密的過(guò)程了: 分析解密lua文件過(guò)程如下:?
????這里需要實(shí)現(xiàn)Lrc4解密的相關(guān)函數(shù),還有Lzma解壓函數(shù)需要自己實(shí)現(xiàn),其他幾個(gè)都是cocos2d平臺(tái)自帶的函數(shù),直接調(diào)用就可以了。上面的流程圖實(shí)現(xiàn)的函數(shù)如下:
bool decryptLua_Mhxy(string strFilePath, string strSaveDir) {bool bResult = false;char *szBuffer = NULL;int nBufferSize = 0;CCFileUtils *utils = CCFileUtils::sharedFileUtils();unsigned long ulFileSize = 0;char *szFileData = (char*)utils->getFileData(strFilePath.c_str(), "rb", &ulFileSize);if (strncmp(szFileData, "L:grxx", 6)){if (!strncmp(szFileData, "__sign_of_g18_enc__", 0x13)){szBuffer = szFileData + 0x13;nBufferSize = ulFileSize - 0x13;bResult = decrypt((unsigned char*)szBuffer, nBufferSize);}}else if (!strncmp(szFileData + 6, "__sign_of_g18_enc__", 0x13)){unsigned char *pData = (unsigned char *)szFileData + 0x19;int nLen = ulFileSize - 0x19;bResult = decrypt(pData, nLen);if (ZipUtils::isGZipBuffer(pData, nLen)){nBufferSize = ZipUtils::ccInflateMemory(pData, nLen, (unsigned char**)&szBuffer);}else if (ZipUtils::isCCZBuffer(pData, nLen)){nBufferSize = ZipUtils::inflateCCZBuffer(pData, nLen, (unsigned char**)&szBuffer);}else if (LzmaUtils::isLzmaBuffer(pData, nLen)){nBufferSize = LzmaUtils::inflateLzmaBuffer(pData, nLen, (unsigned char**)&szBuffer);}else{bResult = false;}}if(bResult)saveLuaData(szBuffer, nBufferSize, strSaveDir);return bResult; }?
? ? ?解密函數(shù)過(guò)程如下:?
?
?????decrypt()實(shí)現(xiàn)代碼如下:
bool decrypt(unsigned char *pData, int nLen) {Lrc4 *pLrc4 = new Lrc4;Lrc4_lrc4(pLrc4);Lrc4_s(pLrc4, pData, nLen);return true; }?
? ? Lrc4結(jié)構(gòu)如下:?
?
? ? ?其他函數(shù)的具體實(shí)現(xiàn)請(qǐng)看DecryptData_Mhxy.cpp文件,這里就不貼代碼了。解密后的文件如下:?
?
?????可以看出,解密后的文件為luac字節(jié)碼,但是這里直接用反編譯工具是不能反編譯luac字節(jié)碼的,因?yàn)橛螒虻膐pcode被修改過(guò)了,我們需要找到游戲opcode的順序,然后生成一個(gè)對(duì)應(yīng)opcode的luadec.exe文件才能反編譯。下表為修改前后的opcode:
?
?????lua虛擬機(jī)的相關(guān)內(nèi)容就不說(shuō)明了,百度很多,這里說(shuō)明下如何還原opcode的順序。首先需要定位到opmode的地方,IDA搜索字符串"LOADK",定位到opname的地方,交叉引用到代碼,找到opmode:
?
?????off_B02CEC為opname的地址,byte_A67C00為opmode的地址,進(jìn)入opmode地址查看:
這里沒(méi)有把全部數(shù)據(jù)截圖出來(lái),可以看出,這里的opmode跟原opmode是不對(duì)應(yīng)的。原opmode在lua源碼中的lopcodes.c文件中:?
?????源碼用了宏,計(jì)算出來(lái)的結(jié)果就是上表中opmode的結(jié)果。這里對(duì)比opmode就可以快速對(duì)比出opcode,因?yàn)閛pmode不相等,那么opcode也肯定不相等,到這一步,已經(jīng)能還原部分opcode了,因?yàn)橛幸恍﹐pmode是唯一的。比如下面幾個(gè):
如SETLIST,原opcode為34,opmode為0x14,找到的opmode的第8個(gè)字節(jié)也為0x14,則實(shí)際上SETLIST的opcode為8。?
?????接下來(lái)就需要定位到luaV_execute函數(shù),然后對(duì)比源碼來(lái)還原其他的opcode,直接IDA搜索字符串"initial value must be a number"可以定位到luaV_execute 函數(shù),再F5一下。接著打開(kāi)lua源碼中的lvm.c文件,找到luaV_execute函數(shù),就可對(duì)比還原了。lua源碼和IDA F5后的代碼其實(shí)差別還是有的,而且源碼用了大量的宏,所以源碼只是用來(lái)參考、理解lua虛擬機(jī)的解析過(guò)程,本人在還原的過(guò)程中,會(huì)再打開(kāi)一個(gè)沒(méi)有修改opcode的libcocos2dlua.so文件,這樣對(duì)比查找就方便多了。
?????最后修改lua源碼 lopcodes.h中的opcode、lopcodes.c的opname和opmode,重新編譯并生成luadec51 .exe(需要將lua源碼中的src目錄放到luadec51的lua目錄下才能編譯),就OK了,寫(xiě)個(gè)批處理文件就可以批量反編譯。一個(gè)文件反編譯的結(jié)果:
?
6.總結(jié)
? ? ?總結(jié)一下解密lua的流程,拿到APK,首先反編譯,查看lib目錄下是否有l(wèi)ibcocos2dlua.so,存在的話很大可能這個(gè)游戲就是lua編寫(xiě),lib目錄下文件最大的就是目標(biāo)so文件,一般情況就是libcocos2dlua.so。接著再看assets文件夾有沒(méi)有可疑的文件,cocos2dx框架都會(huì)把游戲的資源文件放到這個(gè)文件夾下,包括lua腳本。其次分析lua加密的方式并選擇解密腳本的方式,如果可以ida動(dòng)態(tài)調(diào)試,本人一般都會(huì)選擇用idc腳本dump代碼。最后如果得到的不是lua明文,還需要再反編譯一下。
? ? ?不足之處:第一個(gè)是此文是本人逆向lua手游時(shí)的總結(jié),而且本人逆向的手游可能不是很多,所以有些觀點(diǎn)比較片面,不足之處請(qǐng)指正。第二個(gè)就是文章是事后寫(xiě)的,并且寫(xiě)文章的時(shí)間比較倉(cāng)促,所以有些步驟寫(xiě)得可能不詳細(xì),歡迎討論。如果有必要,會(huì)寫(xiě)一篇《如何一步一步還原夢(mèng)幻手游opcode》,但是如果看過(guò)lua源碼,對(duì)lua比較熟悉的話,找出來(lái)我想應(yīng)該不是問(wèn)題的。第三個(gè)就是luajit的反編譯并不完美,用的是luajit-decomp反編譯工具,工具作者也說(shuō)只是滿足了他自己的需求,所以如果可以的話,想自己實(shí)現(xiàn)一個(gè)luajit的反編譯工具,而且夢(mèng)幻luac的反編譯好像部分代碼也反編譯失敗了,可能自己遺漏了點(diǎn)什么吧,就先這樣吧.....(2018/07/10 增加:夢(mèng)幻西游手游lua代碼反編譯失敗的修復(fù)?請(qǐng)點(diǎn)這里)
?
參考文章
騰訊游戲安全中心《Lua游戲逆向及破解方法介紹》?http://gslab.qq.com/portal.php?mod=view&aid=173 云風(fēng)《Lua源碼欣賞》http://download.csdn.net/download/nomoonon/8551481Kaitiren的專欄《Quick-cocos2d-x 與Cocos2dx 區(qū)別》http://blog.csdn.net/kaitiren/article/details/35276177
littleNA《夢(mèng)幻手游部分Luac反編譯失敗的解決方法》?https://litna.top/2018/07/08/夢(mèng)幻手游部分Luac反編譯失敗的解決方法/
轉(zhuǎn)載于:https://www.cnblogs.com/dmeng2009/p/11329258.html
總結(jié)
以上是生活随笔為你收集整理的浅析android手游lua脚本的加密与解密的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: ubuntu 移动硬盘复制小文件可以,复
- 下一篇: java爬虫抓取起点小说,手把手带你爬虫