# cpp_reversed/ 成果总览 > 996传奇客户端 C++ 反编译还原工程 — 阶段 1+2+3 全部交付 > 日期: 2026-09-21 起, 2026-09-23 阶段 3 完成 --- ## 〇、一句话总结 **将 9.6MB stripped arm64 二进制的 C++ 自研层 (mmoclient, 33 类 418 方法) 还原为 9 个可运行的 Python 模块 + 10 份伪 C + 1 个完整接口契约 + 158 项回归测试。** 涵盖网络协议(头编解码/XXTEA/RSA 接口)、脚本密文、地图格式(.map 文件字节级 roundtrip)、寻路(A* 8 方向)、热更下载、批量文本渲染六大子系统。 --- ## 一、产出物全景 ### 1.1 Python 模块 (9 个, ~2.2k 行) | 模块 | 行数 | 来源 | 验证 | 用途 | |---|---:|---|---|---| | `hdr_codec.py` | 74 | encode_header @0x10004b4e4 | 50 组随机 roundtrip | 24B 头 ↔ 32B 编码 | | `xxtea.py` | 193 | LuaBridgeCtl::SetXXTEAKeyGM | 第三方 xxtea 6.2.0 cross-verify | 脚本密文加解密 | | `frame.py` | 226 | netClient::SendNetMessage | 与 protocol_bot 字节级一致 | 36B 头 + body 帧装拆 | | `rsa.py` | 151 | LuaBridgeCtl::RsaEncryptPub/DecryptPri | 接口预留 (密钥待提取) | RSA 客户端本地接口 | | `msg_codec.py` | 232 | 上述聚合 | 33 测试 | 协议编解码统一 API | | `map_parser.py` | 299 | tileSceneManager:LoadMapData | **7/7 .map 字节级 roundtrip** | WGS Mir2 地图解析 | | `path_find.py` | 311 | aiManager:FindPath + Lua A* | 41 测试, 长直道 189 格代价 1890 | A* 寻路 (8 方向) | | `http_downloader.py` | 321 | httpDownloader:AsyncDownloadEx | httpbin.org 1024B 实下载 | 热更/资源下载 | | `label_batch.py` | 142 | LabelBatchNode 22 tolua 方法 | 接口自测 | 批量文本渲染 (数据层) | ### 1.2 r2 伪 C (10 个, ~1.4k 行) | 文件 | 二进制地址 | 函数 | |---|---|---| | `tolua_SendMsg_binding.c` | 0x10007cd54 | tolua 绑定层 | | `LuaNetworkController_SendMsg.c` | 0x10005f8cc | 消息组装 | | `netClient_SendNetMessage.c` | 0x10003d408 | 加密+入队 | | `encode_header.c` / `decode_header.c` | 0x10004b4e4/94 | 头编解码 | | `netClient_recv_loop.c` / `recv_dispatch.c` | 0x100023df8 / 0x10003cd30 | 收包+分发 | | `xor_deobfuscate.c` | 0x100043b34 | XOR 0x10 字符串解混淆 | | `init_keys_and_sign.c` | 0x100043bdc | XXTEA 密钥初始化 (555 行) | | `LuaBridgeCtl_SetXXTEAKeyGM_impl.c` | 0x100044b88 | GM 动态换 key | ### 1.3 接口契约 (1 个, 577 行) `mmoclient_interfaces.h` — 33 类 418 方法 .pkg 风格声明,带分组注释和 tolua 方法名 ### 1.4 文档 (3 个, ~570 行) | 文件 | 覆盖 | |---|---| | `README.md` | 总体说明 + 三档产物 + 用法示例 | | `map_format.md` | .map 文件格式逆向报告 (含 0.map 额外区部分反推) | | `rsa_investigation.md` | RSA 探索全程记录: 7 次搜索失败 → r2 aaa 突破 → 空壳 stub 定论 | | `box_data_passing.md` | 996盒子→游戏数据传递: env.json 双通道 + GN_/NG_ 桥 + CS20 去向 | | `SUMMARY.md` (本文件) | 阶段性成果总览 | ### 1.5 测试 (3 个新文件, 1180 行, 158 项) | 文件 | 测试项 | 范围 | |---|---:|---| | `tests/test_msg_codec.py` | 33 | hdr/xxtea/frame/msg_codec/rsa 协议层 | | `tests/test_map_parser.py` | 38 | map_parser 全部 7 个 .map 样本 | | `tests/test_path_find.py` | 41 | A* 寻路 + 5 个 e2e 地图寻路 | | (原有 28 项无回归) | 28 | 协议桥/调度器/网络桩 | | **合计** | **158** (含 extra_areas 8 项 + header 语义 10 项) | | --- ## 二、按子系统的能力矩阵 | 子系统 | 接口契约 | 伪 C | 可运行实现 | 字节级 roundtrip | 真实 e2e | |---|:-:|:-:|:-:|:-:|:-:| | 网络协议 (头) | ✓ | ✓ | ✓ | ✓ | ✓ (pcap 兼容) | | 网络协议 (帧) | ✓ | ✓ | ✓ | ✓ | ✓ (3 个调用方字节级一致) | | XXTEA | ✓ | ✓ | ✓ | ✓ | ✓ (第三方包 cross-verify) | | RSA | ✓ | — | △ (接口预留) | — | — | | 地图格式 | ✓ | — | ✓ | ✓ | ✓ (7/7 文件) | | 寻路 | ✓ | — | ✓ | — | ✓ (189 格长直道) | | 热更下载 | ✓ | — | ✓ | — | ✓ (httpbin 1024B) | | 批量文本 | ✓ | — | ✓ (数据层) | — | △ (需 cocos2d-x 渲染) | ✓ = 完整还原 / △ = 部分还原 / — = 未涉及 --- ## 三、关键算法速查 ### 3.1 协议头 (24B → 32B) ``` 明文字节 b → ENC_TABLE[b] ^ 9 → 8bit 窗口每次吐 6bit → +0x3C 24B 明文 → 32B 密文 (全 0x3C..0x7B 可打印) ENC_TABLE: 256B, __DATA @0x1008ae5f4 ``` ### 3.2 XXTEA (脚本密文) ``` 8B 块, 16B key, 32 轮, big-endian, delta=0x9E3779B9 padding 0x00 (与 lua lockbox/cipher/tea.lua 一致) 注: 已修正 xxtea-c 参考的 z 未初始化 bug, 严格按 Needham-Wheeler 论文 ``` ### 3.3 地图格式 (.map) ``` 52B header (width/height/title/raw_tail) + (w*h × 12B cells) cell 12B: bg_img(2) + mid_img(2) + obj_img(2) + ani_idx(2) + door_flag(1) + light(1) + area(1) + ani_tick(1) 扩展格式 (title_len=15, 仅 0.map): header + 980000B 2B/cell 稀疏索引 + cells 额外区: 87% 零, 5% 0x8000 标志, 8% 真实 tile 索引 (slot 编码未解) ``` ### 3.4 寻路 (A*) ``` 8 方向, 直线 10 / 对角 14, 启发式 = 欧氏距离² 二叉堆优先队列, 对角穿越自动阻止 (防穿墙) 寻路范围限制 48×32 (与 Lua updateLimits 一致, 长距离需分段) ``` ### 3.5 下载 (httpDownloader) ``` urllib + threading 模拟异步 限速: 令牌桶 (throttle) 进度: callback(downloaded, total) SHA1 校验 (可选) 完整热更流程: download_manifest() + download_update_files(only_changed) ``` --- ## 四、测试覆盖 ```bash # 阶段 1 算法库 (33) + 阶段 2 地图解析 (38+8 extra_areas+10 header语义) + 阶段 3 寻路 (41) + 原有 (28) = 158 总 cd /path/to/传奇 .venv/bin/python -m pytest tests/ -m "not live" -v # 实时下载测试 python3 cpp_reversed/http_downloader.py # 期望: saved 1024B to /tmp/httpdl_test/test.bin # 字节级 roundtrip 验证 python3 -c " import sys; sys.path.insert(0, 'cpp_reversed') from map_parser import load m = load('996传奇盒子资源包/03-游戏客户端/jycq_206923/scene/map/3.map') out = m.to_bytes() orig = open('996传奇盒子资源包/03-游戏客户端/jycq_206923/scene/map/3.map', 'rb').read() print(f'roundtrip: {out == orig} ({len(out)}B)') " ``` --- ## 五、未完成 / 已知缺口 (诚实记录) | 缺口 | 难度 | 解法 | |---|---|---| | ~~客户端本地 RSA 密钥对~~ | ~~中-高~~ | **✅ 已定论 (2026-09-23)**: r2 aaa 完整分析证实 RsaEncryptPub/RsaDecryptPri 是空壳 stub (返回空串), 密钥不存在于二进制。证据链见 `rsa_investigation.md` | | **0.map 额外 980000B 区 slot 编码** | 中 | **⚡ 静态分析已到边界 (2026-09-23 二轮)**: 7 项一组宏图块结构 + V/0x8000 交替已实证; LoadMapData 调用链挖透, 完整槽映射在运行时渲染路径, 需抓内存对照。详见 `map_format.md` §四 | | ~~header 18-51 字段精确含义~~ | ~~中~~ | **✅ 已解 (2026-09-23)**: 7 样本逐字节统计 + 10 项语义测试锁定, 含字节序勘误 (update 时间戳 BE→LE), 详见 `map_format.md` §二 | | **mapData2DRectGrid/Tile3/LightBuffer** | 中 | 与运行时内存表示有关,需场景运行时抓 dump | | **ObjC 壳层** (SDKController) | 中 | 属另一文档范围,需 arm64 ObjC ABI 工具 | --- ## 六、给后续读者的建议 1. **先用 `msg_codec.py` 做抓包分析** — 它 1 行能解出 msgId/recog/params 2. **再用 `map_parser.py` 解析地图** — 7 个样本可立即分析 3. **如果做 bot,** 直接用 `path_find.find_path()` 替代手写 A* 4. **要继续还原 RSA,** 入口是 `cpp_reversed/rsa.py` 的 `INSTALL_HINT` 块 5. **要继续还原 0.map 额外区,** 入口是 `map_format.md` §四 "待精读" 段 6. **要对比 .c 伪代码和 Python 实现,** 任何 `*.c` 文件都对应一个 Python 模块 --- ## 七、版本信息 - 创建: 2026-09-21 (cpp_reversed/ 目录, 10 个 .c + hdr_codec.py + interfaces.h) - 阶段 1: 2026-09-23 (xxtea/frame/rsa/msg_codec 算法库) - 阶段 2: 2026-09-23 (map_parser + map_format.md 地图格式) - 阶段 3: 2026-09-23 (path_find + http_downloader + label_batch) - 收官: 2026-09-23 (SUMMARY.md + README.md 最终版) 最后修改: 2026-09-23 17:09