cocos2dx lua 反編譯(20170417增加補充說明)(轉)


網上各種教程、各種工具用不了,才會有這個文章。附件是我修改的支持luajit 2.1.0-beta2反編譯的LJD

 

lua bytecode解密

 

知己知彼很重要,搜索“cocos2dx lua 加密”大概可以找到類似下面的代碼。

bool AppDelegate::applicationDidFinishLaunching()
{
    ...
 
    CCLuaStack *pStack = pEngine->getLuaStack();
 
    // 如果設置了 -e 和 -ek 要加上下面這句
    // pStack->setXXTEAKeyAndSign("aaa", 3);
    // 如果設置了 -e 和 -ek -es 則要加上下面這句
    pStack->setXXTEAKeyAndSign("aaa", 3, "XT", 2);
    // load framework
    pStack->loadChunksFromZip("res/framework_precompiled.zip");
    pStack->loadChunksFromZip("res/game.zip");
    pStack->executeString("require 'main'");
 
    return true;
}

 

我的目標是一個ANDROID游戲,APK文件直接解壓。一般情況是libcocos2dlua.so,IDA 打開,函數窗口直接搜索applicationDidFinishLaunching,就能帶你飛,可惜只有loadChunksFromZip,沒有setXXTEAKeyAndSign,這保存解密KEY的被編譯優化了。怎么辦?IDA字符串窗口幫你忙,編譯器編譯代碼的時候都是就近原則,只要是差不多地方出現的字符串,都會被放在一起。加密的ZIP文件,文件頭幾個字符就是setXXTEAKeyAndSign的SIGN參數,加上ZIP文件本身的路徑,搜索目標ZIP文件就可以了。如圖,IDA顯示附近也就幾個字符串,剩下的KEY參數是哪個,一個一個試就可以了。

 

加密的ZIP文件:

 

 

IDA中的字符串,第一個黑塊是SIGN參數,非常幸運,嘗試第二個黑塊就是KEY:

 

 

https://github.com/cocos2d/cocos2d-x/search?p=1&q=loadChunksFromZip&type=&utf8=%E2%9C%93 找到cocos2dx的loadChunksFromZip的源碼

 

        if (isXXTEA) { // decrypt XXTEA
            xxtea_long len = 0;
            buffer = xxtea_decrypt(bytes + stack->_xxteaSignLen,
                                   (xxtea_long)size - (xxtea_long)stack->_xxteaSignLen,
                                   (unsigned char*)stack->_xxteaKey,
                                   (xxtea_long)stack->_xxteaKeyLen,
                                   &len);
            zip = ZipFile::createWithBuffer(buffer, len);
        } else {
            if (size > 0) {
                zip = ZipFile::createWithBuffer(bytes, (unsigned long)size);
            }
        }

 

這里我遇到一點困難,cocos2dx的源碼項目,沒有xxtea的源碼!不過還是讓我在github搜索出來了,源碼在此:

 

https://github.com/xxtea/xxtea-c

 

直接寫個C++代碼,就把加密的ZIP解出來了。順帶一提,Sign就是用來跳過,跟什么PE,MZ是一樣的。

 

HANDLE hFileOUT = CreateFile(L"e:\\tmp\\y1\\xxx\\assets\\res\\de_xxx.zip", GENERIC_ALL, 0, 0, CREATE_ALWAYS, 0, 0);
HANDLE hFile = CreateFile(L"e:\\tmp\\y1\\xxx\\assets\\res\\xxx.zip",GENERIC_ALL, 0,0,OPEN_EXISTING,0,0);
if (hFile != INVALID_HANDLE_VALUE)
{
DWORD dwSize = GetFileSize(hFile, 0);
 
size_t  dwOut = 0;
DWORD dwRead = 0;
LPBYTE p = new BYTE[dwSize];
 
ReadFile(hFile, p, dwSize, &dwRead, 0);
DWORD dwSignLen = 3;
LPBYTE p2 = (LPBYTE)xxtea_decrypt((void *)(p + dwSignLen), dwSize - dwSignLen,(void *) "key", &dwOut);
 
 
WriteFile(hFileOUT, p2, dwOut, &dwRead, 0);
delete p;
 
CloseHandle(hFileOUT);
CloseHandle(hFile);
}

 

de_xxx.zip的頭兩個字節變成喜聞樂見的PK,解壓,搞定。

 

Luajit ASM

 

解壓出來的文件,都是LuaJIT— a Just-In-Time Compiler for Lua,文件頭長這樣:

 

 

 

http://luajit.org/download.html 可以下載到LuaJIT的源碼,不過兼容性有點糟糕,需要找到正確的版本才有效。回到IDA字符串窗口搜索luajit,可以確認目標APK使用的是2.1.0-beta2。下載源碼,編譯之后,使用類似下面的命令行:

 

luajit.exe -bl xxx.lua.bytecode xxx.lua.asm

 

可以看到LUA的ASM代碼了,LUA ASM長這樣:

 

0013    TGETV    4   4   1

0014    CALL     3   4   2

0015    ISNEXT   6 => 0019

0016 => MOV      8   7

0017    MOV      9   2

0018    CALL     8   1   2

0019 => ITERN    6   3   3

0020    ITERL    6 => 0016

0021    RET0     0   1

 

BYTECODE的定義在http://wiki.luajit.org/Bytecode-2.0 。不過我智商不夠,看不懂,

 

Luajit decompiler

 

搜索了無數反編譯文章,基本就是https://github.com/NightNord/ljd ,然而這貨2014年之后就再沒更新了,並不能用,沒有選擇,只能自己動手改。

 

1. 由於新Opcode導致的失敗

 

luajit 2.1.0-beta2源碼的lj_bc.h里的#define BCDEF,下方就是長長一串Opcode定義。

 

Ljd源碼的bytecode\instructions.py 和 rawdump\code.py的兩張Opcode表必須跟luajit 2.1.0-beta2 的lj_bc.h一一對比,少了的就要補上。

 

這里不得不吐槽一下luajit,新增Opcode其實並沒有人用,Opcode是通過數組維護的,隨便加個新的Opcode都會導致原有的Opcode編碼改變。。。

 

2. 由於assert導致的失敗,注釋掉就好了。雖說有點不負責,但是反編譯各種語法處理我也不懂。

 

LJD改好之后,main.py xxx.lua.bytecode > xxx.lua,終於可以看到正常的代碼:

 

DeprecatedNetworkClass = {} or DeprecatedNetworkClass
 
local function deprecatedTip(old_name, new_name)
print("\n********** \n" .. old_name .. " was deprecated please use " .. new_name .. " instead.\n**********")
 
return
end
 
DeprecatedNetworkClass.WebSocket = function ()
deprecatedTip("WebSocket", "cc.WebSocket")
 
return cc.WebSocket
end
_G.WebSocket = DeprecatedNetworkClass.WebSocket()
 
return

 

完畢!

 

20170417補充說明:

 

請大家先確認自己的目標,再使用代碼。如果版本不一致,你們需要先對比luajit源碼中的lj_bc.h和https://github.com/NightNord/ljd的bytecode\instructions.py 和 rawdump\code.py中的OPCODE表,對得上,才能正確反編譯,對不上就自己參照着來改。

 

 

 

上傳的附件:
  •  ljd-master2.1.0b2.7z (84.45kb,745次下載)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM