
逆向工程实战Frida动态分析Cocos游戏中的XXTEA加密机制在移动应用安全研究领域游戏逆向分析一直是个充满挑战又极具价值的方向。特别是使用Cocos引擎开发的游戏其核心逻辑往往通过JavaScript代码实现再编译为字节码形式存储。这些jsc文件通常会被加密保护而XXTEA作为一种轻量级加密算法因其高效性和实现简单成为Cocos开发者常用的加密方案。本文将系统性地介绍如何利用Frida这一动态插桩工具从运行中的Cocos游戏中提取XXTEA加密密钥为安全研究人员提供一套可复用的方法论。1. Cocos游戏逆向分析基础1.1 Cocos引擎的代码组织特点Cocos Creator开发的Android应用具有明显的文件结构特征lib目录通常包含libcocos.so等核心库文件assets目录存放游戏资源、脚本和加密的jsc文件jsc文件JavaScript字节码文件游戏逻辑的主要载体# 典型Cocos游戏目录结构 assets/ ├── main.jsc ├── src/ │ └── *.jsc lib/ └── arm*/libcocos.so1.2 XXTEA加密在Cocos中的应用XXTEACorrected Block TEA是一种分组加密算法具有以下特点特性说明密钥长度128位16字节分组大小64位8字节运算速度快适合移动设备实现复杂度低代码量小在Cocos引擎中常见的XXTEA相关函数包括jsb_set_xxtea_key设置加密密钥xxtea_decrypt解密函数xxtea_encrypt加密函数2. 动态分析工具链配置2.1 Frida环境搭建Frida是一款强大的动态插桩工具我们需要配置以下环境安装Frida工具包pip install frida-tools准备Frida-server下载与手机架构匹配的版本推送到设备并运行adb push frida-server /data/local/tmp/ adb shell chmod 755 /data/local/tmp/frida-server adb shell /data/local/tmp/frida-server 2.2 目标应用准备分析前需要确保目标应用已root或可调试了解应用包名和主Activity准备好adb调试环境提示对于非root设备可以考虑使用frida-gadget注入方式3. 关键函数Hook实战3.1 定位加密函数通过静态分析初步定位关键函数使用IDA分析libcocos.so搜索xxtea相关函数导出重点关注Game::init等初始化函数3.2 Frida脚本编写以下是完整的Hook脚本示例function hookJava() { Java.perform(function() { var Cocos2dxActivity Java.use(com.cocos.lib.CocosActivity); Cocos2dxActivity.onLoadNativeLibraries.implementation function() { this.onLoadNativeLibraries(); hookNative(); } }); } function hookNative() { var decryptFunc Module.findExportByName(libcocos.so, xxtea_decrypt); if (decryptFunc) { Interceptor.attach(decryptFunc, { onEnter: function(args) { // args[2]通常对应密钥参数 var key Memory.readUtf8String(args[2]); console.log([] XXTEA Key Found: key); // 可以进一步记录调用堆栈 console.log(Thread.backtrace(this.context, Backtracer.ACCURATE) .map(DebugSymbol.fromAddress).join(\n)); } }); } } hookJava();3.3 密钥提取技巧在实际操作中密钥提取可能遇到以下情况密钥硬编码直接出现在函数参数中运行时计算需要跟踪密钥生成过程多密钥切换不同场景使用不同密钥对于复杂情况可以扩展脚本Interceptor.attach(Module.findExportByName(libcocos.so, jsb_set_xxtea_key), { onEnter: function(args) { console.log(Key set to:, Memory.readUtf8String(args[0])); } });4. 静态分析与动态调试结合4.1 静态分析辅助动态获取密钥后可以结合静态分析在IDA中搜索获取到的密钥字符串定位密钥引用位置分析密钥使用上下文4.2 解密验证获取密钥后可以使用以下工具验证XXTEA解密工具import xxtea data open(encrypted.jsc, rb).read() decrypted xxtea.decrypt(data, key) open(decrypted.jsc, wb).write(decrypted)浏览器调试将解密后的js代码在浏览器控制台测试4.3 网络协议分析结合抓包工具如Charles/Fiddler分析确认通信数据是否使用相同密钥加密检查加密前后数据变化规律构建自动化加解密流程5. 进阶技巧与问题排查5.1 常见问题解决方案问题现象可能原因解决方案Hook失败函数名错误检查导出符号密钥无效编码问题尝试不同编码格式崩溃参数错误检查参数类型和数量5.2 性能优化建议使用Frida的NativePointer高效读取内存避免在Hook回调中执行耗时操作合理使用Thread.safe修饰回调5.3 反调试对抗某些游戏会检测Frida常见对抗措施重命名frida-server使用非常规端口定时检测内存特征对应的Hook脚本调整// 绕过常见的反调试检测 var pthread_create Module.findExportByName(null, pthread_create); Interceptor.attach(pthread_create, { onEnter: function(args) { var path Memory.readUtf8String(args[3]); if (path.indexOf(frida) ! -1) { args[3] ptr(0); } } });6. 实际案例分析在一次商业游戏分析中我们发现密钥并非直接传递而是通过特定算法生成每次启动时密钥会变化加密函数被混淆处理解决方案// Hook密钥生成函数 var keyGenFunc Module.findBaseAddress(libcocos.so).add(0x123456); Interceptor.attach(keyGenFunc, { onLeave: function(retval) { console.log(Generated key:, Memory.readUtf8String(retval)); } }); // 动态修改加密行为 var encryptFunc Module.findExportByName(libcocos.so, xxtea_encrypt); Interceptor.replace(encryptFunc, new NativeCallback(function(data, len, key) { console.log(Encrypt called with key:, Memory.readUtf8String(key)); return 0; }, int, [pointer, int, pointer]));7. 工具链扩展与自动化为提高效率可以构建自动化分析工具链自动Hook脚本import frida def on_message(message, data): if message[type] send: print([*], message[payload]) session frida.get_usb_device().attach(com.game.package) with open(hook.js) as f: script session.create_script(f.read()) script.on(message, on_message) script.load()批量解密工具#!/bin/bash for file in *.jsc; do xxtea -d $file -k $KEY -o ${file%.jsc}.js done协议分析框架集成class GameProtocol: def __init__(self, key): self.key key def decrypt(self, data): return xxtea.decrypt(data, self.key)在实际项目中我们发现最有效的密钥提取时机往往是在游戏资源加载阶段此时密钥会被频繁使用且较少有反调试检测。通过合理设置Hook点和优化脚本性能可以大幅提高分析效率。