Mas0n
to be reverse engineer🐧
翻车鱼

浅谈Cocos2d-x下Lua文件的保护方式

浅谈Cocos2d-x下Lua文件的保护方式

好久没整LUA啦,最近翻到了一篇文章,比较详细的介绍了LUA文件的保护方式

我也粗略的了解了一点Lua的保护形式,才有了一篇《解密Cocos2d-x默认保护形式下的LUAC》,并且写了一份脚本调用

然而事实上,XXTEA的保护形式只是LUA保护方式之一,这也就是这篇文章的起始点咯

Lua文件的保护形式

目前主流的Lua文件的保护形式有以下三种:

  • 对称加密
    打包在应用安装包中的 Lua 脚本经过加密,应用加载 Lua 脚本前先进行解密而后运行脚本,通过解密就可以获取 Lua 脚本源代码。
    解密后也可能获得的是 Luac 字节码,文件头为 0x1B 0x4C 0x75 0x61 0x51,这是将 Lua 脚本预编译成二进制文件,从而提升加载速度,需要再进行一次反编译才可以获得 Lua 脚本源代码。
  • 编译 LuaJIT 字节码并加密
    JIT 指的是 Just-In-Time(即时解析运行),文件头为 0x1B 0x4C 0x4A。LuaJIT 使用了一种全新的方式来编译和执行 Lua 脚本。经过处理后的 LuaJIT 程序,字节码的编码实现更加简单,执行效率相比 Lua 和 Luac 更加高效。
    开发者将 Lua 脚本编译成 LuaJIT 字节码,而后再加密 LuaJIT 字节码,应用先进行解密后加载 LuaJIT 字节码。这种方式能够较好的保护 Lua 脚本源代码,反编译存在一定门槛。
  • 打乱 Lua 虚拟机中 OpCode 顺序或修改引擎逻辑
    通过修改 Lua 源代码,将 Lua 脚本预编译成 Luac 字节码,可以理解为重新映射 Lua 虚拟机执行指令,实现门槛较高,无法通过通用工具进行反编译。
    需使用 IDA 定位到虚拟机的 OpMode 和 luaV_execute 函数,通过对比原先 Lua 虚拟机的执行过程,分析出修改后的 OpCode 顺序才可以编译生成反编译工具。

先介绍一下cocos2dlua默认的加密方式叭~(咕咕咕,字节码和Opcode的坑以后填)

XXTEA加密算法

如果开发者使用了 Cocos2d-x 框架自带的 XXTEA 加密算法

那摸,可以通过以下几种方法来获得 Lua 脚本源代码:

  • 静态分析 so 库
    使用 IDA 定位到 luaL_loadbuffer 函数后向上回溯,分析脚本解密过程后制作解密工具。
  • 动态调试 so 库
    使用 IDA 动态调试,定位到 luaL_loadbuffer 地址并下断点,应用会在启动时调用 luaL_loadbuffer 函数加载必要的 Lua 脚本,断下后即可将 Lua 脚本源代码导出。
  • Hook so 库
    Hook 方式与动态调试原理类似,通过 Hook 函数 luaL_loadbuffer 地址实现 Lua 脚本源代码导出。
    动态调试每次只能获取单个 Lua 脚本源代码,如果使用 Hook 只需运行一次即可全部导出。

更快的方法?

XXTEA 加密算法需要 Key 和 Sign 才可以进行解密,但是由于 Cocos2d-x 框架的设计原因,导致这个加密形同虚设,所以有一个取巧的办法可以快速获取 Key 和 Sign
获取 Sign 只需随意打开一个 .luac 后缀的加密文件,在文件头看到的一串字符串便是 Sign

Key 也是个字符串,藏在 libcocos2dlua.so 文件中,打开 IDA ,能在刚刚得到的 Sign 值附近得到 Key

Q:为什么可以取巧?
A:通过 Cocos2d-x 的源代码可以了解到开发者需要调用 setXXTEAKeyAndSign 函数进行文件解密,Key 和 Sign 都是在同一函数进行调用,所以生成 so 库时,这两个字符串也在一起。
另外也可以使用 IDA 载入 libcocos2dlua.so 文件,在 String 中搜索 Sign 值,一般 Key 就在附近,如果附近字符串均无法解密的话,亦可尝试暴力枚举。

当然啦,Hook setXXTEAKeyAndSign 函数也是拿到Key和Sign的一种方法,我在引文中也展示了Frida下Hook的脚本和解密工具,这里就不再赘述了

字节码的反编译

咕咕咕

总结一下

由于 Cocos2d-x 框架自身设计原因,自带的加密解决方案只防君子,不防小人,可轻易实现对游戏客户端进行调试、修改等操作,建议通过上文介绍的源代码保护方式自定义加密。

LUAJIT 2.0.3/2.1.0beta3 Opcode的比对和校验

最近浅析了一下luajit,想要实现下反编译,通过万能的度娘,我发现网上的文章大多都是17年甚至更前,不过干货不会过期,在非虫大佬的lua_re系列文章中,可以了解到关于luajit编译后的文件的字节码的剖析,然而对于我这样,喜欢用轮子但又有着煤渣技术的人来说,寻找轮子必不可少

2021-04-09

通过非虫大佬的分析文章,可以了解到luajit文件的结构,但是使用010Editor模板并不易阅读,有没有能够反编译出代码形式的轮子呢?

搜索引擎用起来~ 前辈们主要使用的工具:

多数文章介绍并使用了以上几种工具,然而这些工具早已停止维护,ljd更是在2014年停止维护,不过查看这些文章也并不是一无所获:通过修改luajit对应版本的Opcode就能进行不同版本的反编译

随着luajit版本的迭代,其Opcode会改变,具体可以查看LuaJit仓库的src/lj_bc.h找到相应的Opcode

我对比了版本2.0.3以及截止撰写文章前正式发布的最新版本2.1.0beta3的Opcode

https://cdn.shi1011.cn/2021/04/44e097c8a939b36ee4bc73c5c003acf7.png?imageMogr2/format/webp/interlace/0/quality/90|watermark/2/text/wqlNYXMwbg/font/bXN5aGJkLnR0Zg/fontsize/14/fill/IzMzMzMzMw/dissolve/80/gravity/southeast/dx/5/dy/5

看到原有的Opcode并没有删除或修改,只是增加了几条新Opcode,在ljd项目中,只需更改rawdump/code.pybytecode/instructions.py中的opcode

关于luajit版本的查找:一般的,使用IDA加载Shift+F12或直接使用010搜寻luajit就能查询到版本信息

https://cdn.shi1011.cn/2021/04/35e98ff88192561d1e404cdd1c989053.png?imageMogr2/format/webp/interlace/0/quality/90|watermark/2/text/wqlNYXMwbg/font/bXN5aGJkLnR0Zg/fontsize/14/fill/IzMzMzMzMw/dissolve/80/gravity/southeast/dx/5/dy/5

基于ijd项目,我找到了衍生至最近时间的一个项目luajit-decompiler,支持目前luajit正式发布的所有版本2.0.x,2.1.x,我fork了作者的仓库,有部分的更改,贴上地址

后续可能会分析下轮子的原理…下次下次!(逃了)

…….

参考

本文链接:https://blog.shi1011.cn/rev/android/1216
本文采用 CC BY-NC-SA 4.0 Unported 协议进行许可

Mas0n

文章作者

推荐文章

发表回复

textsms
account_circle
email

翻车鱼

浅谈Cocos2d-x下Lua文件的保护方式
好久没整LUA啦,最近翻到了一篇文章,比较详细的介绍了LUA文件的保护方式 我也粗略的了解了一点Lua的保护形式,才有了一篇《解密Cocos2d-x默认保护形式下的LUAC》,并且写了一份脚本调…
扫描二维码继续阅读
2021-04-09