☰
逆向停服手游第一步:Lunar Tear 如何解密主数据 .bin.e(AES + LZ4 + msgpack 全拆解)
2026/10/15 17:43:13 网站建设 项目流程

【免费下载链接】lunar-tear

Private server research project for a certain discontinued mobile game

项目地址:https://gitcode.com/gh_mirrors/lu/lunar-tear
点击查看免费下载

停服手游的客户端里通常藏着一份"主数据"(Master Data):角色、武器、抽卡池、任务、商店……所有配置都打包在一个加密压缩的二进制文件里。Lunar Tear 是一个针对某款已停服手游的私服研究项目,它的核心工作之一就是逆向并解密主数据 .bin.e 文件,用 AES-CBC 解密 + msgpack 解析 + LZ4 解压三步打通完整链路。本文带你完整拆解这条数据链路的每一步,以及解密后的数据如何被服务器热加载。

一份 .bin.e 是什么?

游戏客户端首次启动时会向 CDN 请求下载主数据文件。Lunar Tear 的 CDN 服务(octo-cdn)就原样提供这个文件,代码位于 octo.go:

  • 文件固定存放在assets/release/20240404193219.bin.e(文件名中的数字是版本号yyyymmddHHMMSS)
  • URL 里的{version}段只作为客户端缓存键,磁盘上永远只有这一个.bin.e
  • 服务器端则直接从该路径读取并解密,见 main.go

也就是说:.bin.e=加密 + 压缩 + 序列化三件套叠加的"套娃"文件。

解密流水线总览

整个逆向过程可以浓缩成一条流水线(全部实现在 memorydb.go):

.bin.e 密文 │ ① AES-128-CBC 解密 + PKCS7 去填充 ▼ 明文 │ ② 解析 msgpack 目录头(表名 → [偏移, 长度]) ▼ 目录 TOC + 数据区 data blob │ ③ 每张表:msgpack ext(code=99) → LZ4 解压,或直接解析普通数组 ▼ []struct 强类型 Go 结构体

下面逐步拆解。

第一步:AES-CBC 解密

打开 memorydb.go 就能看到逆向得到的"钥匙",直接以十六进制常量写死在代码里:

aesKeyHex = "36436230313332314545356536624265" // 16 字节 → AES-128 aesIVHex = "45666341656634434165356536446141" // 16 字节 IV

解密逻辑(memorydb.go)要点:

  1. 模式:AES-128-CBC,cipher.NewCBCDecrypter(block, iv)
  2. 校验:密文长度必须是 16 字节的整数倍(CBC 分块大小)
  3. 去填充:解密后执行 PKCS7 Unpadding(pkcs7Unpad),校验末尾填充字节全部合法,防止"差一位"的脏数据静默通过

💡 新手提示:AES-CBC 是"分组密码 + 链式加密"。解密只需要密钥和 IV,但 IV 错了会导致第一块解密结果全乱——这也是逆向时最先验证的参数。

第二步:解析 msgpack 目录头

AES 解密出来的并不是直接的数据表,而是一个msgpack 编码的 map,充当"目录"(TOC):

{ "m_weapon": [偏移, 长度], "m_gacha_medal": [偏移, 长度], "m_config": [偏移, 长度], ... }

解析实现在 parseHeader:

  • 先用msgpack.NewDecoder把第一个 msgpack 对象解成map[string]interface{}
  • 每个 value 必须是[offset, length]二元数组
  • 通过"解密前总长 − 解码器剩余字节数"算出目录本身占了多少字节,剩余部分就是数据区 data blob

之后每张表只需按dataBlob[off : off+length]切片取出原始字节,并校验off + length不越界(memorydb.go)。

第三步:LZ4 解压(msgpack ext 类型)

每张表有两种可能的编码形态,decompressAndUnmarshal 会先"偷看"(peek)首字节再分流:

形态特征处理
LZ4 压缩表首个对象是 msgpack ext,类型码99(0x63)先解 LZ4 块,再解内层 msgpack
明文表普通 msgpack 数组直接 Unmarshal

LZ4 ext 内部还有一层小"表头"(readLZ4ExtHeader):第一个字节标记解压后尺寸的编码方式:

  • 0xd2/0xce:大端 int32 / uint32 尺寸(5 字节头)
  • <= 0x7f:正 fixint,尺寸就在这一字节里

拿到尺寸后分配缓冲区,调用lz4.UncompressBlock解压,最后msgpack.Unmarshal到强类型切片。

第四步:从字节到强类型 Catalog

解密后的原始字节最终要变成 Go 结构体。表结构由schemas.json生成,见 entities.go(文件头注明Code generated by scripts/gen_entities.py):

// EntityMAbility is table key "m_ability". type EntityMAbility struct { AbilityId int32 AbilityLevelGroupId int32 }

各业务模块用泛型工具函数按"表名"取数,例如抽卡模块(gacha.go):

utils.ReadTableEntityMGachaMedal utils.ReadTableEntityMMomBanner

入口只有一个:utils.ReadTable →memorydb.ReadTableT。

解密之后:热加载与版本广播

这是 Lunar Tear 比普通"离线解密脚本"更进一步的地方——解密结果被包装成可原子热切换的运行时快照:

  1. runtime/holder.go:Holder持有atomic.Pointer[Catalogs],Reload()时重新memorydb.Init整个文件、从零重建全部 Catalog,再一次性原子发布。所有 gRPC 服务每次 RPC 开头调Get(),永远看到一致快照。
  2. admin.go:管理 WebhookPOST /api/admin/master-data/reload(默认仅监听127.0.0.1:8082),需LUNAR_ADMIN_TOKEN环境变量设置后才会绑定——"fail-closed"设计,未配置 token 时端口根本不开放,且 token 比较使用常量时间算法防时序侧信道。
  3. 版本字符串联动:data.go 中GetLatestMasterDataVersion把文件的mtime拼进版本号。Reload()会os.Chtimes刷新 mtime,客户端下一次轮询就会发现"版本变了",主动从 CDN 重新下载.bin.e(CDN 侧正是 serveDatabaseBinE 提供文件)。

于是形成闭环:改文件 → 调 Webhook → 内存原子换新 → 版本号变化 → 客户端自动拉取新数据,全程无需重启服务器。

涉及模块速查表

环节文件说明
AES 密钥/IV、解密主流程memorydb.goInit/decrypt/parseHeader
LZ4 ext 解压memorydb.godecompressAndUnmarshal
表结构定义(生成代码)entities.go由schemas.json生成
读表入口utils.goReadTableT
热加载 Holderholder.go原子快照切换
管理 Webhookadmin.gotoken 门控的热重载端点
版本号广播data.gomtime 拼入版本字符串
CDN 分发 .bin.eocto.goserveDatabaseBinE

总结

逆向停服手游主数据的完整链路,本质上就是回答三个问题:

  1. 怎么解密?→ 找到 AES-128-CBC 的密钥与 IV(16 字节十六进制常量),PKCS7 去填充
  2. 怎么定位数据?→ 解密出的 msgpack map 就是目录,[偏移, 长度]直接切片
  3. 怎么读出来?→ 识别 msgpack ext 类型码99即 LZ4 压缩,解压后再解 msgpack 到强类型结构

Lunar Tear 的价值在于把这条逆向链路工程化了:生成式实体代码、泛型读表接口、原子热加载、token 门控的管理端点和 mtime 版本广播,让"解密 .bin.e"从一次性实验变成了可持续维护的私服基础设施。如果你正在做类似项目,不妨对照 memorydb.go 的四个函数逐段阅读——那大概就是全文最短的"主数据解密教程"。

【免费下载链接】lunar-tear

Private server research project for a certain discontinued mobile game

项目地址:https://gitcode.com/gh_mirrors/lu/lunar-tear
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询