ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Cocos解密实战:APK解包、AssetBundle提取与脚本还原全流程

2026/9/7 11:53:58 拓冰建站 浏览量
Cocos解密实战:APK解包、AssetBundle提取与脚本还原全流程 Cocos 项目开发到后期最让人头疼的一类问题就是“东西找不到了”APK 是以前打好的源码却因为电脑重装、成员离职、仓库清理而丢失AssetBundle 更新包还在线上原始美术资源却没有备份想排查线上包某个功能逻辑只能对着编译后的 JS 文件发愁。这篇文章要聊的“cocos解密”并不是网上那种破解商业游戏、绕过付费校验的思路而是指对 Cocos Creator 项目构建产物做资源还原、代码梳理和结构分析的完整流程。它适用于自己开发的项目、有合法授权的项目以及学习研究场景。本文会以 Cocos Creator 3.x 的产物结构为主线围绕 APK 解包、JSBundle 还原、AssetBundle 资源提取和自定义加密脚本处理展开并提供可直接运行的 Python/Node.js 示例脚本。文章内容较长建议收藏后按章节阅读。需要说明的是标题中的日期只是标记写作时间Cocos Creator 的版本迭代很快实际操作请以你本机安装的 Creator 版本为准本文示例以 Cocos Creator 3.8.x 为参考环境。1. 什么是 Cocos 项目“解密”1.1 解密的概念边界在 Cocos 社区里“解密”这个词有几种不同的含义很多新人容易混淆。第一种是资源解密。Cocos Creator 构建后的资源文件如图片、图集、音频、JSON 配置通常以原始或轻度压缩的形式存储在 APK 或 AssetBundle 中。所谓“解密”就是把这些资源从打包产物中提取出来还原成可以在 Creator 编辑器中重新导入的格式。第二种是脚本解密。Cocos Creator 2.x 时代游戏逻辑脚本会被编译成 main.js、settings.js 等文件3.x 时代则会生成按 Bundle 组织的 .js 文件。为了让代码不被轻易阅读不少项目会自己实现一层异或XOR或 AES 加密。脚本解密的本质是找到自定义加密算法并还原出可读代码。第三种是数据解密。部分项目会把配置表、存档数据、排行榜数据用自定义算法加密解密后用于排查线上问题或恢复数据。这里要特别强调合法边界解密行为只应该针对自己开发的游戏项目或者已经获得授权的项目。未经授权对商业游戏进行逆向、提取素材、破解逻辑不仅违反用户协议也可能触犯相关法律法规。本文的所有示例都使用虚构的项目名和片段不针对任何真实游戏产品。1.2 常见的解密场景根据我在社区和日常开发中接触到的案例需要做 Cocos 项目“解密”的场景主要有这几类场景典型需求说明源码丢失恢复只剩 APK没有 .js/.ts 源码从 APK 中还原资源和脚本恢复可维护工程素材备份找回原图/音频原始文件丢失从 AssetBundle 提取 PNG、JPG、MP3、JSON线上包排查线上包逻辑与本地不一致对比构建产物定位哪个 Bundle 更新出了问题学习研究研究 Cocos 产物组织方式解构构建产物理解 3.x 的资源加载机制安全自查检查自己的包是否存在泄露风险站在逆向视角找出可被提取的敏感信息1.3 涉及的主要产物类型Cocos Creator 构建发布后核心产物有以下几类APK / AABAndroid 安装包本质是一个 ZIP 容器里面包含 res、assets、lib 等目录。assetsCocos 构建的核心资源目录包含 src脚本、assets资源、settings.json、native 等。AssetBundle以 .bundle 结尾的目录或文件内部包含资源 JSON 描述、图片、音频等内容。JSBundle存放脚本逻辑的打包产物通常是合法的 JavaScript 代码。native 目录原生层代码和第三方库的 so 文件。理解这些产物的组织方式是后续所有“解密”操作的基础。2. 环境准备与工具链2.1 软件工具清单做 Cocos 产物分析不需要太重的环境。以下工具按用途分类列出均可在各自官方网站获取工具用途类型Node.js运行还原脚本、处理 JS 产物运行时Python 3写自定义解密脚本处理二进制运行时jadx查看 APK 中的 Java/Kotlin 代码GUI/命令行apktool解包 APK查看资源和 smali命令行7-ZipZIP/APK/AssetBundle 预览与解压桌面工具VS Code查看脚本代码、搜索关键字IDE如果只需要提取资源7-Zip 加一个文本编辑器就够了。如果涉及脚本逻辑还原建议安装完整工具链。2.2 安装与版本说明版本需要根据你的项目实际情况调整这里以我常用的组合为例操作系统Windows 11 / Ubuntu 22.04 Node.js18.x 或 20.x LTS Python3.10 或更高 jadx1.4.x 或更新版本 apktool2.9.x Cocos Creator3.8.x安装完成后在终端确认环境node -v python --version java -version apktool --version如果命令无法识别需要检查环境变量配置。Windows 下注意把工具所在目录添加到 PATH。2.3 解包 APK 的基础操作先用 apktool 解包一个 APK观察目录结构。注意这里针对的是你手里有合法处理权的 APK 文件。apktool d MyCocosGame.apk -o apk_out执行后会出现apk_out目录。Cocos Creator 项目的资源主要在两个位置apk_out/assets/Cocos 的资源目录。apk_out/lib/包含libcocos.so等原生库。更快的预览方式是直接改扩展名为 .zip用 7-Zip 打开。APK 本身就是 ZIP 格式这种方式不会影响文件结构。3. 核心原理Cocos Creator 构建产物是怎么组织的要做好“解密”先要理解构建产物里的文件是怎么来的。这部分的原理清楚了后面遇到任何新结构都不慌。3.1 2.x 与 3.x 的差异Cocos Creator 2.x 的构建产物中脚本被编译到src/main.js和src/settings.js资源则分散在assets目录。整体结构简单解包后基本可以直接看到脚本。Cocos Creator 3.x 开始引入 Asset Bundle 机制构建产物发生很大变化assets/ ├── main/ │ ├── config.json │ ├── index.js │ └── assets/ ├── resources/ │ ├── config.json │ ├── index.js │ └── assets/ ├── src/ │ ├── chunk/ │ ├── system.js │ └── ... ├── settings.json └── native/每个 Bundle 有独立的config.json和index.js。config.json描述资源路径、UUID、压缩类型等信息index.js是 Bundle 的初始化脚本。3.2 脚本是如何编译的Cocos Creator 的脚本在构建时会被 TypeScript 编译器转成 JavaScript再通过 rollup 等工具打包成index.js或系统脚本。3.x 的脚本代码在src/system.js、src/chunk/*.js等文件中。理论上这些 JS 是可以直接用文本编辑器查看的但实际项目中脚本可能经过两类处理压缩混淆变量名变成短名字、空格换行被删除。自定义加密对 JS 内容做 XOR、AES 或 Base64 变种直接打开是乱码。判断方法是看文件开头。正常 JS 通常以注释或代码起始加密后的文件可能是十六进制字符、Base64 字符串或者明显无序的二进制内容。3.3 资源文件的存储形式Cocos Creator 3.x 的资源不会原样存放。图片可能被压缩为spriteFrame描述文件加纹理图音频可能转成.mp3或.wavJSON 配置通常会按__c字段保存类型描述。在 Bundle 的assets目录下会看到很多.json文件内部结构示例{ __type__: cc.SpriteFrame, _name: hero_icon, _texture: { __uuid__: 8a1c..., __expectedType__: cc.Texture2D } }这些 JSON 描述文件与实际的 PNG 纹理是分开存储的通过 UUID 关联。提取时不能只拿 PNG还要保留 JSON 描述才能完整还原成一个可在编辑器中使用的资源。3.4 自定义加密类型的识别判断自定义加密算法核心是观察字节分布。常用方法用十六进制编辑器打开文件看前几个字节。如果开头有PK说明是 ZIP 子包。如果内容是可见字符但不像代码可能是 Base64。如果字节分布均匀且出现大量0x00或重复字节可能是异或加密。对于异或加密可以通过已知明文攻击来恢复密钥。比如 Cocos 的 JS 文件通常以use strict或注释开头用这些已知片段与密文异或就能得到密钥的一部分。4. 实战还原自己项目的 Cocos APK下面进入可操作环节。以一个虚构的MyCocosGame.apk为例演示完整的资源与脚本还原流程。4.1 解包 APK 并定位 Cocos 目录把 APK 复制到工作目录然后解压mkdir cocos_unpack cd cocos_unpack cp /path/to/MyCocosGame.apk . apktool d MyCocosGame.apk -o apk_out实际操作中我习惯先用 7-Zip 直接打开 APK因为 apktool 会把 XML 转成可读格式但 Cocos 资源是二进制apktool 处理起来会慢一些。先确认assets下是否存在main、resources等目录。4.2 提取 Cocos 资源进入apk_out/assets使用 Node.js 写一个批量复制脚本把resources和main中的资源提取到extracted目录// 文件extract_assets.js // 用法node extract_assets.js inputDir outputDir const fs require(fs); const path require(path); const inputDir process.argv[2]; const outputDir process.argv[3]; if (!inputDir || !outputDir) { console.error(请输入输入目录和输出目录); process.exit(1); } function walkAndCopy(current, base) { const entries fs.readdirSync(current, { withFileTypes: true }); for (const entry of entries) { const fullPath path.join(current, entry.name); const relPath path.relative(base, fullPath); const destPath path.join(outputDir, relPath); if (entry.isDirectory()) { fs.mkdirSync(destPath, { recursive: true }); walkAndCopy(fullPath, base); } else { fs.mkdirSync(path.dirname(destPath), { recursive: true }); fs.copyFileSync(fullPath, destPath); console.log(提取:, relPath); } } } fs.mkdirSync(outputDir, { recursive: true }); walkAndCopy(inputDir, inputDir); console.log(提取完成);运行node extract_assets.js apk_out/assets extracted这一步之后extracted目录中会得到 Bundle 的config.json和资源 JSON 描述但图片可能还是经过压缩或拆分的纹理需要进一步解析config.json才能还原资源名。4.3 还原脚本 JS 代码如果src下的 JS 没有加密可以直接用文本编辑器打开但它是压缩过的。先用 Prettier 做格式化npx prettier --write extracted/src/system.js格式化后代码会变得可读。变量名仍然是压缩过的短名字但逻辑结构基本能看懂。如果项目保留了 sourcemap还原效果会更好不过大多数发布包不会带 sourcemap。如果 JS 文件是乱码说明做了自定义加密。下面是一个异或解密的 Python 示例适用于密钥为单字节或短字符串的简单场景# 文件xor_decrypt.py # 用法python xor_decrypt.py encrypted.js output.js key import sys def xor_decrypt(data: bytes, key: bytes) - bytes: key_len len(key) if key_len 0: return data result bytearray(len(data)) for i in range(len(data)): result[i] data[i] ^ key[i % key_len] return bytes(result) if __name__ __main__: if len(sys.argv) ! 4: print(用法: python xor_decrypt.py input.js output.js key) sys.exit(1) input_file sys.argv[1] output_file sys.argv[2] key sys.argv[3].encode(utf-8) with open(input_file, rb) as f: encrypted f.read() decrypted xor_decrypt(encrypted, key) with open(output_file, wb) as f: f.write(decrypted) print(f解密完成: {output_file})运行示例python xor_decrypt.py encrypted_system.js system_decoded.js CocosKey4.4 解析 AssetBundle 中的资源AssetBundle 的config.json是整个 Bundle 的资源索引。下面用 Python 脚本解析打印出所有资源的 UUID、路径和压缩类型# 文件parse_bundle_config.py # 用法python parse_bundle_config.py config.json import json import sys def main(): if len(sys.argv) ! 2: print(用法: python parse_bundle_config.py config.json) sys.exit(1) with open(sys.argv[1], r, encodingutf-8) as f: config json.load(f) packs config.get(packs, {}) paths config.get(paths, {}) types config.get(types, {}) print( Bundle 打包组 ) for pack_name, pack_data in packs.items(): print(f包名: {pack_name}, 包含 {len(pack_data)} 个资源) print(\n 资源路径映射 ) for uuid, path_index in paths.items(): # paths 中的值是路径在 types 数组中的索引 if isinstance(path_index, int) and path_index len(types): print(fUUID: {uuid} - {types[path_index]}) if __name__ __main__: main()运行python parse_bundle_config.py extracted/resources/config.json注意不同 Creator 小版本的config.json会略有差异但packs、paths、types这几个字段基本是一致的。4.5 处理自定义加密脚本后的工程化还原在实际项目中很多团队会在构建后增加一步“脚本加密”流水线npm 脚本大致如下{ scripts: { build:encrypt: cocos build -p web node scripts/encrypt.js build/web/assets/src } }加密脚本的思路通常是遍历目标目录下的.js文件读取内容后做异或或 AES 加密再写回文件。还原这类加密项目的关键是找到加密脚本本身或者从构建机的 CI 配置里定位密钥。如果手上只有 APK没有密钥可以从 APK 内的 Java 层代码里找线索。用 jadx 打开 APKjadx -d jadx_out MyCocosGame.apk然后在jadx_out/sources目录搜索关键字比如xor、key、decrypt、assetsgrep -r decrypt jadx_out/sources --include*.java -l如果密钥写在 Java 层这一步基本能定位。如果密钥只存在于 JS 层则需要先还原 JS 代码再从代码中搜索字符串常量。4.6 还原后的工程重建建议完成资源提取和脚本还原后得到的并不是一个可以直接用 Cocos Creator 打开的原工程。要重建工程需要做好几件事创建新 Cocos Creator 工程版本尽量与构建时一致。将还原的.json、.png、.mp3等资源按 Bundle 对应目录放回assets/resources或assets/main。将还原的.js文件转为.ts或作为插件脚本引入。在编辑器中逐个检查资源引用是否完整。这一步工作量大但相比完全重写仍然能保留大量美术资源和部分业务逻辑。5. 常见问题与排查思路5.1 常见报错排查表问题现象常见原因解决思路APK 解压后找不到 assets/main项目使用了不同 Bundle 名称查看 assets 下所有目录识别自定义 BundleJS 文件打开是乱码脚本被自定义加密识别加密类型尝试异或或 AES 解密config.json 解析报错Creator 版本不同字段结构差异打印原始 JSON观察关键字段名图片提取后无法显示图片被压缩或拆分为纹理使用 config.json 重建纹理图集解密后 JS 语法错误密钥错误或格式未去掉头信息检查文件头部是否有自定义标记头jadx 打开 APK 报错使用了加固壳或混淆尝试先脱壳或检查 lib 层逻辑Bundle 提取后资源引用 UUID 丢失只提取了文件没有处理 config.json按 config.json 的 UUID 重写资源路径5.2 解密脚本后代码仍然无法理解这是一个很常见的情况尤其是发布包经过 rollup 打包后代码结构会和源代码差异很大。我的经验是不要试图“完全还原源码”而是定位关键逻辑。例如先搜索 URL 地址、事件名、接口路径、cc.API 调用等关键字再逐步梳理业务逻辑。5.3 大概率遇到的权限问题如果是在 Linux 服务器上操作解包后资源可能没有读权限。运行chmod -R 755 extracted/Windows 下如果遇到文件被占用关闭 7-Zip 或文本编辑器再执行覆盖操作。6. 安全加固如何加密你自己的 Cocos 项目解密和加密是硬币的两面。理解了攻击者如何还原资源就更容易制定防御策略。下面几个加固方向适用于自己维护的正式项目。6.1 代码混淆构建后对 JS 进行混淆是成本最低、效果最明显的防护方式。{ scripts: { build:release: cocos build -p android --mode release node scripts/obfuscate.js } }混淆脚本可以使用 javascript-obfuscatornpm install --save-dev javascript-obfuscator// 文件scripts/obfuscate.js const fs require(fs); const path require(path); const JavaScriptObfuscator require(javascript-obfuscator); const targetDir process.argv[2] || build/android/assets/src; function walk(dir) { fs.readdirSync(dir).forEach((name) { const full path.join(dir, name); if (fs.statSync(full).isDirectory()) { walk(full); } else if (name.endsWith(.js)) { const code fs.readFileSync(full, utf-8); const obfuscated JavaScriptObfuscator.obfuscate(code, { compact: true, renameGlobals: true, stringArray: true, stringArrayEncoding: [base64], }).getObfuscatedCode(); fs.writeFileSync(full, obfuscated); console.log(混淆完成:, full); } }); } walk(targetDir);6.2 资源加密图片、音频等大资源不适合整体强加密因为解密会影响加载性能。更实用的做法是对敏感配置 JSON 做加密并在代码中通过自定义加载管线解密。// 文件assets/scripts/EncryptedJsonLoader.ts import { resources } from cc; export async function loadEncryptedJsonT(path: string, key: string): PromiseT { return new Promise((resolve, reject) { resources.load(path, (err, textAsset) { if (err) { reject(err); return; } try { const encrypted textAsset.text; const decoded xorDecode(encrypted, key); resolve(JSON.parse(decoded) as T); } catch (e) { reject(e); } }); }); } function xorDecode(input: string, key: string): string { let result ; for (let i 0; i input.length; i) { result String.fromCharCode(input.charCodeAt(i) ^ key.charCodeAt(i % key.length)); } return result; }6.3 AssetBundle 加密与校验AssetBundle 通常走远程加载建议增加两个机制一是下载后校验 MD5防止文件被替换二是对敏感逻辑脚本使用 AES 加密在原生层解密。加密脚本示例# 文件encrypt_bundle.py # 用法python encrypt_bundle.py input.bundle output.bundle key import sys from Crypto.Cipher import AES from Crypto.Util.Padding import pad def aes_encrypt_file(input_file: str, output_file: str, key: bytes): cipher AES.new(key, AES.MODE_CBC) with open(input_file, rb) as f: data f.read() encrypted cipher.encrypt(pad(data, AES.block_size)) with open(output_file, wb) as f: f.write(cipher.iv) f.write(encrypted) if __name__ __main__: key sys.argv[3].encode(utf-8) aes_encrypt_file(sys.argv[1], sys.argv[2], key) print(加密完成)注意AES 密钥不要硬编码在 JS 层。推荐放在原生层生成或从服务端动态下发否则攻击者通过 jadx 查看 JS 代码就能找到密钥。6.4 检查泄露面上线前可以自己按本文流程解包一遍自己的 APK重点检查下面几项是否能在assets/src直接看到可读 JS。是否能在 APK 中找到数据库、API Key、账号密码等敏感信息。是否有未加密的config.json暴露服务器地址和 Bundle 列表。JS 代码中是否包含可被搜索到的内部注释和调试日志。用攻击者的视角检视自己的包往往能发现很多死角。7. 总结与学习建议围绕“cocos解密”本文完整梳理了 Cocos Creator 构建产物的目录结构、APK 解包流程、JS 脚本还原、AssetBundle 资源解析和自定义加密脚本的处理思路并在最后一节反过来给出了代码混淆、资源加密、AssetBundle 校验等加固方案。对 Cocos 开发者来说解密能力最大的价值不是去分析别人的游戏而是让自己在源码丢失、素材缺失、线上包异常时能快速自救。接下来可以继续深入的方向有三个一是系统学习 Cocos Creator 3.x 的 Asset Bundle 加载机制理解config.json和resources的关系二是研究 APK 的完整构建流程从构建脚本反推每种产物文件的来源三是练习 JavaScript 混淆与反混淆提升阅读压缩代码的能力。实际操作中优先关注敏感信息泄露风险和脚本加密密钥的管理这两点是大多数 Cocos 项目最容易忽略的隐患。最后提醒一句如果你要解密的项目不是自己开发的务必先确认授权范围。技术本身是中性的但使用技术的方式决定了边界。动手练习时建议用自己构建的测试工程开始先把本文的流程走通一遍再应对复杂的真实场景。