apktool源码如何编译-Android手游lua脚本加密解密分析

0. 前言

本文是我在学习Android手游安全时总结的一篇关于lua的文章。 不足之处敬请谅解,欢迎大牛前来交流。 本文目录如下:

0. 前言

1、手游中lua脚本的现状

2.lua、luac、luaJIT文件之间的关系

3.Lua脚本保护

3.1 普通对称加密,加载脚本前揭晓

3.2 将lua脚本编译成luaJIT字节码但加密打包

3.3 修改lua虚拟机中opcode的顺序

4.获取lua代码的常用技巧

4.1 静态分析揭示方法

4.2 动态调试:ida + idc + dump

4.3 钩子

4.4 分析lua虚拟机的操作码顺序

5、揭秘三款游戏的lua脚本过程

5.1 54 钓鱼

5.2 钓鱼大师4

apktool源码如何编译-Android手游lua脚本加密解密分析

5.3 梦幻西游手游

六、总结

参考文章

主要使用的工具和环境:

1.Win7系统一

2、Quick-cocos2d-x开发环境(方便学习的一个开发环境,大部分lua手游都使用cocos2d-x框架,还有一个用处,可以在源码的关键函数中查看特征字符串,然后在IDA中定位关键函数就非常方便了)

3.IDA6.8(分析so文件+动态调试so)

4.vs2015(写秘码)这里推荐使用vs2013来编译运行cocos2d-x,vs2015有太多的坑需要填......

5、AndroidKiller 1.3.1(反编译apk,其中apktool.exe为最新版本)

6. luadec51(反编译luac)

7. luajit-decomp(反编译luaJIT)

ETC...

1、手游中lua脚本的现状

轻微地。

2.lua、luac和luaJIT文件之间的关系

apktool源码如何编译-Android手游lua脚本加密解密分析

在学习lua手游的过程中,我遇到的lua文件大部分就是这三种类型。 其中lua是纯文本代码,可以直接用记事本打开,luac是lua编译后的字节码,文件头为0x1B 0x4C 0x75 0x61 0x51,lua虚拟机可以直接解析lua和luac脚本文件,并且luaJIT 是 lua 的另一个实现版本(不是原作者写的),JIT 指的是 Just-In-Time(即时解析并运行),luaJIT 比 lua 和 luac 效率更高,文件头为 0x1B 0x4C 0x4A。

卢阿克:

卢吉特:

3.Lua脚本保护

一般有安全意识的游戏厂商不会直接将lua源码脚本打包成APK来发布,所以对lua脚本的保护通常有以下三种:

3.1 普通对称加密,加载脚本前揭晓

这种情况意味着APK中打包的Lua代码是加密的,程序在加载Lua脚本时就会泄露秘密(关键函数luaL_loadbuffer),只有解密后才能获取Lua源代码。 如果泄密后得到了luac字节码,那么通过反编译也可以得到lua源码。 反编译主要使用的工具是unluac和luadec51,后面会详细分析。

3.2 将lua脚本编译成luaJIT字节码但加密打包

因为反编译的结果不容易检查,这些情况可以更好地保护lua源代码。 这种情况,解密后反编译即可。 反编译主要是通过luajit-decomp项目,该项目也可以将luajit字节码反编译为伪lua代码。

3.3 修改lua虚拟机中opcode的顺序

这种情况主要是改变lua虚拟机的源代码,然后通过改变后的虚拟机将lua脚本编译成luac字节码,从而达到保护的目的。 这种情况下apktool源码如何编译,如果直接使用之前的反编译工具反编译luac,则需要分析程序中对应的opcode,然后改变lua工程的opcode的顺序,重新编译生成反编译工具,然后就可以反编译了是的,我们稍后会详细分析。

一般都会跨越之前的情况。

4.获取lua源码的常用技巧

这里我们主要介绍四种方法,将在第五节中举例说明。

4.1 静态分析so解密方法

这种方法需要分析揭秘的整个过程,费时费力。 主要方法是通过ida定位到luaL_loadbuffer函数,然后回溯分析泄密的过程。

4.2 动态调试:ida + idc + dump

这里我们主要使用ida来动态调试so文件,然后定位到luaL_loadbuffer地址。 游戏启动时会通过调用luaL_loadbuffer函数加载必要的lua脚本。 通过在luaL_loadbuffer中设置断点,可以运行idc脚本转换lua代码导入(程序调用一次luaL_loadbuffer加载一个lua脚本,如果idc脚本不写,需要自动导入N次...) 。

4.3 钩子

原理和4.2一样,都是通过钩子函数luaL_loadbuffer地址来保存代码。 与4.2相比,游戏过程中需要加载一些lua脚本。 如果使用4.2,则需要在游戏过程中自动中断一次。 运行一次 idc 脚本,通常一次只加载一个 lua 文件。 如果是钩子的话,就不用那么麻烦了。 只要玩一次游戏,所有的lua脚本就已经被保存了。

4.4 分析lua虚拟机opcode的顺序

这里的主要原因是操作码的顺序已经改变。 需要使用ida定位虚拟机执行luac字节码的地方,然后对比原来lua虚拟机的执行流程,获取修改后的opcode顺序,最后恢复lua脚本。

5、三款游戏lua脚本揭秘示例

好,我们用3个例子来说明一下里面的情况。

5.1 54 钓鱼

首先用AndroidKiller加载,然后查看lib目录下的so文件,发现libcocos2dlua.so文件基本都是lua脚本编译出来的。 这里有一个小方法。 当so文件很多时,一般最大的文件就是我们的目标(文件大是因为集成了lua引擎)。 既然有lua引擎,就一定有lua脚本,然后寻找lua脚本。 资源文件和lua脚本文件都在assets目录下。 发现游戏的资源文件和配置文件都是明文的,这里可以通过直接改变游戏的配置文件来作弊(比如改变升级要塞所需的金币和砖块就可以达到目的)快速升级炮台的方法),然后没有找到类似Lua脚本的文件。

我解压res目录下的liveupdate_precompiled.zip,发现解压失败。 好像是加密的(从名字就知道是更新游戏的代码)。 这是一个解释。 一般这些满足xxxx_precompiled.zip的文件都是quick-cocos2d-x框架(quick简单来说就是lua的扩展),在quick-cocos2d-x框架下,可以使用compile_scripts命令将lua文件加密打包成xxxx_precompiled.zipapktool源码如何编译,然后在游戏运行时加载。注意,这样打包的lua脚本通常会被编译成luaJIT。 加载的关键函数是loadChunksFromZIP。 你可以直接在IDA中搜索这个函数。 如果找不到,可以搜索字符串 luaLoadChunksFromZIP 来定位该函数。

OK,明白原理后,开始手工分析,将libcocos2dlua.so拖到IDA中加载,在函数中直接搜索loadChunksFromZIP,定位后F5。

一路往下走(交叉引用),来到右图,找到泄露出来的秘钥和签名,其中xiaoxian是秘钥,XXFISH是签名。

进入函数看一下,其实你会发现调用的是XXTea算法。 这里我们也可以直接分析loadChunksFromZIP函数的源码(所以配置一个cocos2d开发环境是非常有必要的)。 查看源码中lua_loadChunksFromZIP函数的原型:

intCCLuaStack::lua_loadChunksFromZIP(lua_State*L)

if(lua_gettop(L)m_xxteaSignLen,

(xxtea_long)大小-(xxtea_long)堆栈->m_xxteaSignLen,

(unsignedchar*)stack->m_xxteaKey,

(xxtea_long)stack->m_xxteaKeyLen,

&len);

删除[]zip文件数据;

zip文件数据=NULL;

zip=CCZipFile::createWithBuffer(buffer,len);

...

接下来直接写secret函数(cocos2d-x项目上写的secret函数,很多工具都可以直接调用)

voiddecryptZipFile_54BY(stringstrZipFilePath)

CCFileUtils*utils=CCFi​​leUtils::sharedFileUtils();

无符号longlZipFileSize = 0;

无符号字符 * szBuffer = NULL;

unsignedchar*zipFileData=utils->getFileData(strZipFilePath.c_str(),"rb",&lZipFileSize);

xxtea_longxxBufferLen=0;

szBuffer=xxtea_decrypt(zipFileData+6, //6为签名XXFISH的宽度

(xxtea_long)lZipFileSize-(xxtea_long)6,//减去签名的宽度

(unsignedchar*) "xiaoxian", //xiaoxian 是密钥

(xxtea_long)8,//键的宽度

&xxBufferLen);

// 获取zip中的所有文件

CCZipFile*zipFile=CCZipFile::createWithBuffer(szBuffer,xxBufferLen);

整数计数=0;

stringstrFileName=zipFile->getFirstFilename();

while(strFileName.length())

库特

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 源码编译 apktool源码如何编译-Android手游lua脚本加密解密分析 https://www.wkzy.net/game/169218.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务