看雪论坛
发新帖
14

[原创]cocos2dx lua 反编译(20170417增加补充说明)

笨笨雄 2017-4-1 17:33 4759

网上各种教程、各种工具用不了,才会有这个文章。附件是我修改的支持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文件,文件头几个字符就是setXXTEAKeyAndSignSIGN参数,加上ZIP文件本身的路径,搜索目标ZIP文件就可以了。如图,IDA显示附近也就几个字符串,剩下的KEY参数是哪个,一个一个试就可以了。


加密的ZIP文件:

 

 

IDA中的字符串,第一个黑块是SIGN参数,非常幸运,尝试第二个黑块就是KEY

 


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


        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


解压出来的文件,都是LuaJITa 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

 

可以看到LUAASM代码了,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表,对得上,才能正确反编译,对不上就自己参照着来改。


上传的附件:
本主题帖已收到 2 次赞赏,累计¥101.00
最新回复 (38)
rongkao 2017-4-1 18:03
2
厉害啊!!
caolinkai 2017-4-3 20:09
3
caolinkai 2017-4-3 20:11
4
图片挂了
聖blue 2017-4-4 02:22
5
不错!!!!!!
14
笨笨雄 2017-4-5 08:52
6
caolinkai 图片挂了
已修复图片
2
littlewisp 2017-4-5 13:30
7
多谢版主分享
朝舞菌 2017-4-5 19:27
8
看得我一脸蒙蔽2333333
DragKing 2017-4-6 14:14
9
崇拜的笨笨雄大神归来     
jecray 2017-4-9 14:11
10

请问为什么报错啊?

rongkao 2017-4-10 15:31
11

楼主  能说说  那个  py的  脚本  要怎么用?  我试了  好久都不能用,  用了个  luajit  2.1.0-beta2    在加密  脚本  也没办法解 

上传的附件:
jecray 2017-4-12 21:03
12
求群主明示啊
冰封之子 2017-4-13 15:25
13
jecray 请问为什么报错啊?
一样的报错  不知为啥
Fido 2017-4-14 16:04
14
学习咯~~~~~~~~~~~~
Sam.com 2017-4-15 02:19
15
谢谢分享
marsboys 2017-4-15 09:11
16
谢谢分享
14
笨笨雄 2017-4-17 09:24
17
jecray 请问为什么报错啊?
需要先确定  LUA的版本,  不同版本,字节码不一定一样
14
笨笨雄 2017-4-17 09:29
18
rongkao 楼主  能说说  那个  py的  脚本  要怎么用?  我试了&am ...
你这个下载早了,再下载一次附件吧,解压之后是“XXX-副本”,你出错的代码是我调试时遗留下来的
wooyunking 2017-4-17 11:09
19
楼猪6666
rongkao 2017-4-17 11:09
20
笨笨雄 你这个下载早了,再下载一次附件吧,解压之后是“XXX-副本”,你出错的代码是我调试时遗留下来的
恩恩  好的  谢谢的大神
fengmaple 2017-4-18 13:24
21
请问一下‘utf-8’  codec  can't  decode  byte  ****:invalid  start  byte    这个应该怎么解决呢?
ranhoo 2017-4-19 21:59
22

楼上的,utf-8问题我也碰到,是你的文件没有debug信息,解析时多读了这部分,所以出错,把对应py文件中解析debug部分注掉即可。另,解析很多if跳转的文件还是会生成不了

具体是rawdump/prototype.py下面的几行注释掉,如下图:

ranhoo 2017-4-19 22:17
23

我类似这样的文件老是编译不了,因为if太多可能,老是出错,楼主能否帮忙看下?

----补充说明

  看了下,是在逻辑表达式处理这块上有点弱,会报错。看来这个不好修复了。郁闷。作者自己也说了:

There is a lot of work to do, in the order of priority

0. Logical subexpressions in while statements:
 ```lua
  while x < (xi and 2 or 3) do
   print ("Hello crazy world!")
  end
 ```

3. Features not supported:
 1. GOTO statement (from lua 5.2). All the required functionality is
  now in place, but that's rather a low-priority task right now.

 2. Local sub-blocks:
 ```lua
 do
  ...
 end
 ```

上传的附件:
fengmaple 2017-4-20 10:38
24
ranhoo 楼上的,utf-8问题我也碰到,是你的文件没有debug信息,解析时多读了这部分,所以出错,把对应py文件中解析debug部分注掉即可。另,解析很多if跳转的文件还是会生成不了 ...
感谢指点
MaYil 2017-4-20 16:13
25
感谢分享!!!
miyuecao 2017-4-25 10:16
26
看得云里雾里的,高手就是个高手
HoHooHo 2017-4-27 13:40
27
楼主  python用的哪个版本  多少位的    一直报错啊 
starrrk 2017-5-11 18:42
28
ranhoo    你的问题解决了没有?我遇到的问题和你类似
14
笨笨雄 2017-5-14 09:28
29
我并没有打算写一个反编译工具。。。解释失败的文件,我直接看字节码版的。。。
starrrk 2017-5-16 18:29
30
楼主的这个回复真是让人心碎啊
pansalily 2017-5-19 23:54
31
厉害了我的哥
gtict 2017-5-23 19:50
32
楼主大神,,有没有研究过Python改个opcode的游戏!!
Deemoxl 2017-6-11 15:05
33
pop  from  empty  list请问楼主这个错误是怎么引发的啊?
大宝章法王 2017-6-12 23:10
34
大神  大神    大神  方便留您的qq吗?有偿求教啊    大神
技术那些事 2017-6-13 10:58
35
大神    大神        大神    方便留您的qq吗?有偿求教啊        大神
大宝章法王 2017-6-13 21:38
36
大神  救我  !
醉赤壁 2017-6-14 15:48
37

和10楼同样的问题,lua的加密版本还特意找了和楼主提供的luajit版本一致,但还是报错,不知道为什么?

xxRea 2天前
38
太厉害了,最近也在做Lua反编译相关的事情·~受教了
1
daiweizhi 16小时前
39
版本一致,多有的被我注释掉了,运行py代码错误  :Failed  to  read  prototype怎么解决版主?这是什么问题根据你写的教程已经修改了opcode和两个py文件了运行就提示这个Failed  to  read  prototype
返回



©2000-2017 看雪学院 | Based on Xiuno BBS | 知道创宇带宽支持 | 微信公众号:ikanxue
Time: 0.017, SQL: 14 / 京ICP备10040895号-17