记一次半吊子逆向工程的…艰难过程
前言
在搞小游戏的过程中需要一些美术资源,从网上购买了一些不是很满意,所以准备对几个精品同类手游下手,捞一手美术资源。
下手
一个某大话私服手游,解压安装包:
1 | ├── AndroidManifest.xml |
打开 lib 目录,下面三个目录对应不同 CPU 架构。
- arm64-v8a
第 8 代 64 位 ARM 处理器,是以后的架构的趋势。 - armeabiv-v7a
第 7 代及以上的 ARM 处理器,目前是主流架构。 - x86 / x86_64
32 位架构,模拟器用的比较多
1 | ├── arm64-v8a |
通过libcocos2dlua.so
可以确定游戏引擎是 Cocos2d-Lua 。
如果有
libmono.so
,libil2cpp.so
等文件,则可能是 Unity 。
res 目录一般是 Android 工程的 Icon、Logo 等文件(忽略)。assets/res 是我们要找的资源目录,随便挑一张图片文件打开是这样的:

通过文本编辑器打开内容是这样的:

打开多个文件发现头都是sm!fd9%3nX4@
这几个字符,基本确定是 XXTEA 算法(这是 Sign,我们需要找到 Key 就可以进行解密资源)。
分析
通过 IDA 工具进行分析,拖入 libcocos2dlua.so 等待分析完成。

点击 View->Open Subviews->Strings,CTRL + F 搜索sm!fd9%3nX4@
,如果能够搜到就最简单,双击sm!fd9%3nX4@
进入 Hex View 页面能看到 Key 就在附近。

如果没有搜索到,重新搜索xxtea
,列表中_Z13xxtea_encryptPhjS_jPj
、_Z13xxtea_decryptPhjS_jPj
这俩就是 xxtea 加解密的函数。

逆向方案
确定是 XXTEA 算法之后,有两种方式来获取 Key
- IDA 动态调试
附加进程进行断点调试获取 - Frida
注入 Hook 脚本获取
两种方式流程大致相同,其原理都是注入程序读取内存之后通过端口进行转发,但是 Frida Hook 相比较容易一些。
准备工作:
安卓设备 / 模拟器(本文使用的 Mumu 模拟器)
游戏安装包(需要开启 debug 模式)
其他
- IDA 动态调试:Java 1.8、Android SDK、Android Device Monitor
- Frida Hook:Python
Frida Hook
- 安装 Frida 环境
1 | $ pip3 install frida |
- 下载 Frida Server
https://github.com/frida/frida/releases
frida-server-16.2.1-linux-x86_64.xz
- 模拟器开启 root 权限,打开 USB 调试模式。
1 | $ cd /Applications/NemuPlayer.app/Contents/MacOS |
- 查看游戏包名
1 | # cd /data/app |
- 启动 Frida Server
1 | cd /data/adb |
- 测试服务
1 | $ frida-ps -U |
- 运行 Hook 脚本
1 | const libName = "libcocos2dlua.so"; |
1 | $ frida -U -f www.cocos.game -l ./key.js |
gb4sZzoV/fP2P)t3
这个就是 XXTEA 算法的 Key。
IDA 动态调试
有时间补充进来
解密资源
Cocos2d-x 关于 XXTEA 的 Lua 资源解密流程
CCLuaStack.cpp
1 | int LuaStack::luaLoadBuffer(lua_State *L, const char *chunk, int chunkSize, const char *chunkName) |
根据逻辑可以推出,根据加密资源头部 Sign 来确定是否 XXTEA 加密,解密时把 Sign 忽略。实现如下:
1 | sign := "sm!fd9%3nX4@" |

最后
附上示例:cocos2d-reverse
Q&A
- adb shell 提示 error: no devices/emulators found
1 | $ ./adb kill-server |