返回
查看原链接原链接
Bilibili1小时3分20秒 · —

洛克王国助手开发手记

《洛克王国》Flash游戏辅助框架的搭建与解析笔记

本项目并非面向普通玩家的现成外挂,而是一套面向开发者的、基于 C++ + CEF + JS 架构的 Flash 游戏辅助开发框架——作者逆向分析了《洛克王国》的 Flash 协议与资源结构,整理出 600 余个网络协议,实现了数据包拦截、修改、转发、ACL 返回内容篡改等核心能力,使开发者可以像写前后端一样用 JS 快速开发各种辅助功能。

项目背景与定位

起因

  • 作者(瑞哥)近期因工作繁忙暂停更新视频,但在业余时间做了一个小游戏助手。
  • 目标游戏为《洛克王国》(Rock Kingdom),属于 Flash 网页游戏。
  • 触发点:作者吃饭时喜欢看直播,无意间刷到洛克王国直播,觉得“节目效果挺好”,且该游戏是童年回忆(小学初中时期),因此产生了做助手的兴趣。
  • 游戏现状:非常老旧,且仍为 Flash 游戏。

定位说明

  • 并非面向广大普通玩家:作者明确说明这个助手不是给一般玩家使用的现成辅助工具,使用起来不像网上现成的辅助那样傻瓜式。
  • 面向开发者:整套框架需要一定的开发经验才能使用;没有开发经验想直接应用的话,建议使用市面成品方案。
  • 作者评价成品类的旧方案:大多基于“按键精灵/易语言”等方式在语言层面处理,开发方式“太老太老”,“不是这个时代的产品开发”。

技术选型与整体框架

底层语言:C++

选择 C++ 的原因:

  1. 内存操作能力强:做助手的基础功能(如内存读取、HOOK 等)需要这一类底层语言的支持。
  2. 向上层语言隐藏细节:使用 C++ 做底层后,上层语言不需要关注很多操作细节。
  3. 个人使用习惯:作者写多了习惯了 C++,但也承认“并没有太大特别大的优点”,换其他语言“其实也无所谓”。
  4. 需求驱动——想用 CEF:作者希望使用 Chromium Embedded Framework(谷歌开源内核),而 Windows 上通过传统 WebBrowser 控件(IE 内核)的方式“极差”“非常不安全”——既然要运行 Flash 游戏,安全性需要做好,因此选择了 CEF。

上层语言:JS

  • 通过 CEF 提供上层 JS 语言支持,开发者可以自己编写 JS。
  • 上层辅助功能全部用 JS 实现——辅助界面本质上是一个网页。
  • 甚至可以搭建 Web 服务,把网址填入框架,即可动态修改和增加功能。

后端:无限制

  • 有了 JS 之后,后端语言“无所谓”,可自行选择。
  • 作者示例中使用了 Python 相关技术(文中提到 Flask、FastAPI 等),后端仅做了简单示例。

GUI 框架:Qt(QSS 美化)

  • 界面基于 Qt 开发,使用 QSS(Qt 样式表)寻找开源主题。
  • 作者评价:找到开源主题后整体还算漂亮,其他更漂亮的主题需要付费——经判断是国内开发者的作品,作者选择不付费,“免费开源吧”,自己做了调整。

开发者工具入口

  • 在框架界面中按 F12 可打开开发者工具(DevTools),支持查看页面、修改样式、Console 打印等操作。
  • F12 开发者工具在 Flash 开启后会涉及不同的子进程类型——如 render(渲染)进程、broker 进程等,整体结构比较复杂,作者默认未开启该功能,原因是防止使用者做不当修改且调试复杂。

Flash 版本兼容性探究

浏览器/CEF 对 Flash 的支持现状

  • 现代浏览器几乎均不再支持 Flash 插件。
  • 实测 360 浏览器支持 Flash,但作者不愿意下载安装 360 浏览器。
  • 作者测试发现:CEF 86 版本是最后一个支持 Flash 的版本;此后版本已明确“不允许使用”Flash(“禁止”而非“不支持”)。
  • CEF 86 版本虽支持,但存在很大限制。
  • 作者实际使用的 Flash Player 版本为 308(最新版),该版本虽官方不再维护,但作者提到“貌似好像还有自己一些开发者在维护”,可用于一些特殊的高级操作。
  • Flash Player 76 开头版本(如 76/77)可以通过右键设置“自动运行 Adobe Flash Player”,但 86 版本无法通过加命令行参数强制自动运行,只能采用右键选择“运行此插件”的方式。

游戏资源提取浏览器

  • 作者使用 360 浏览器 加载游戏并进行资源抓取/分析,因为现代普通浏览器已不支持 Flash。
  • 抓取手段:搭配一个付费软件(支持抓包/资源导出的逆向工具)对企业版进行了功能增强。

Flash 游戏资源逆向分析

资源下载与整体规模

  • 作者将洛克王国的 Flash 资源整体脱取下载下来,数据量很大。
  • 脱取时使用了相对高的 CEF 版本(86 版本作为浏览器内核)。
  • 随后使用工具对资源进行分析处理。

关键文件加密与破解方法

  • 游戏关键资源(SWF 文件)存在一层小加密——在一个非常关键的 A 按键/文件 中存在加密逻辑,复杂度较高,直接拖取文件困难。
  • 解决思路借鉴了 DX 逆向(游戏逆向中“内存爆破”类技术):在内存中搜索指定特征码,找到后将其脱出。
  • 解锁 Flash 资源的导出能力:原本用于分析的付费软件,个人版不支持导出功能;企业版功能不够完善,作者自行为该软件增加了一个“全部导出”功能支持。

游戏代码框架评估

  • 核心逻辑包:以 com 开头的最为关键,下面有 tenant 等子包,再往下是 QQ Angela 相关包,属于核心处理逻辑;其余属于渲染等用途。
  • 编程语言:Flash 使用的 ActionScript(AS 语言)。作者此前不会 AS,但阅读后发现该语言“语法极其简单”,“基本上你不需要去学习”,“只要会 JS 就能看懂”。
  • 整体框架质量:在当时年代已经算是非常优秀的框架,采用了类似注册机制的设计。
  • 重要发现——框架被破坏:由于游戏运营时间长、经历多代开发人员迭代,原本搭建良好的框架被各种改动所“破坏”,丧失了原本简洁清晰的风格;各代开发人员的更新很不协调。

框架演变:从统一协议到多套并存

游戏数据包协议经历了多代变迁,形成了多套数据包格式并存的局面:

  1. 早期(正规/简洁时代)
  • 原本是一个正常 Socket + 数据包(ADF 包)结构,有 ADF 基类(ADF Base)。
  • 数据包结构:一个固定标识(ADF 头)+ 结构体头 + Body 内容。
  • Body 中每个实例实现 update/input/output 方法(一个输入一个输出);字段包含 flag 标识、protect ID 等。
  • 根据 flag 作分发处理。
  • 编码方式:数据包使用 short 等方式进行字段编解码(类似 Flash 自制的序列化/反序列化)。
  1. 中期(风格分裂)
  • 后续改造后,除了原有 plus 包下逻辑外,又新增了 Skt 包(位于 com 包下某个 net 包中)。
  • Skt 系列不再继承原来的类,改而继承 CtoS 等;包结构变化很大,但“本质上还是一样的”(数据交互本质没变),只是风格改变。
  • 作者表示这种情况可以接受,“只是框架变了,但数据包交互本质上还是一样”。
  1. 后期(引入 Protobuf)
  • 出现大量 PB 开头的内容——引入了 Protobuf(Google Protocol Buffers)作为新的序列化方案。
  • 特征非常明显(典型的 protobuf 结构)。
  • Protobuf 数据包需用 protobuf 库解析,手动解析不推荐。
  • 作者通过字段名(如 ReadFrom 等)初步判断后确认,并将其还原为原本的 protobuf 结构。
  1. HTTP/ACL 类请求
  • 第三种数据包类型是 ACL/HTB 格式——本质上是 C++ 风格的一种 HTTP 类请求(命名方式参考了 C++ CGI 风格),包含大量 XML 文件交互(作者顺带下载了大量 SWF 文件,即通过 XML 清单脚本批量下载的)。
  • ACL 请求可返回大量 XML 内容,修改这些返回内容可以实现特殊功能(如替换 XML、清空内容等)。
  • 存在 GET/POST 等类型区分,需要处理请求和回复两侧。

协议类型总结

协议类型载体/格式出现阶段备注
结构体类协议ADF 头 + 结构体 + body(T / XT / Skt 等命名)早期至中期使用 short 等方式编解码,继承体系因时代不同而变化
PB 协议Protobuf后期300+ 个协议,需用 protobuf 库解析,可用反射机制处理
ACL/HTB 协议HTTP 类请求(C++ 风格命名/XML 内容)后期带 GET/POST 参数、需拦截请求与回复、回复可改造

协议规模

  • 作者共整理协议 600 多个
  • 其中 XT/T 类型约 300 多个,PB 类型约 300 多个。
  • 说明:最终展示的列表中仅看到 300 来个是因为部分协议(尤其是 PB 中的)字段没有合适命名而没有写入展示列表,并不代表总量只有这些。

底层功能实现与技术难点

数据包拦截机制

  1. 为何需要多种拦截:由于数据包类型多达三种(结构体型、PB 型、ACL 型),要实现数据截断、截持和更新,必须分别处理。
  2. Socket API 拦截的发现历程
  • 作者最初使用 send/receive(send/receive)方式。
  • 切换到 CEF(Chromium 嵌入式框架)后发现:Flash 并没有使用标准 send 函数,而是使用 Windows 的异步 I/O(如 `WSASend` 等 Windows 异步 Socket 机制)
  • CEF 框架对异步 I/O 有封装和支持(虽然 CEF 86 是 2018 年左右的产物,但功能比较完善),但存在 bug(会出现一些奇怪的异常问题)。
  1. 最终实现方式:作者把数据包截取后,包括定位请求在内,全部一股脑转发给上层 JS——由 JS 自行修改、展示或再发包。底层 C++ 代码只需要作者维护即可,上层开发者无需关注 C++ 侧实现。

600 多个协议的手工分析过程

  • 协议分析工作量大且极其繁琐。
  • 作者每天下班晚上回家就开工,一步步对照,最终“把 800 多个[实为 600 多个]一点点全干出来了”。
  • 结构体类协议靠特征识别:先识别 ADF 头,再看返回码/数组数量,逐一编码为 C++ 结构体。
  • 代码量极大:某些协议定义文件长七八千行。“没有任何难度,它只是非常反锁 [繁琐]”。
  • 辅助工具:
  • BASE Struct 文件包含通用结构体类型。
  • 真正的特殊结构体(如 T 开头系列)单独定义,内容很长。

Protobuf + Qt 的内存问题(技术坑)

  • 项目中使用了 Qt 和 Protobuf 两套依赖,均使用 MT(多线程静态链接)方式
  • 当 Protobuf 升级到第 8 版本时,与 Qt 的 MT 方式兼容性出错(作者不确定是 bug 还是编译特殊指令导致)。
  • 现象:使用反射机制处理消息时,返回的 stringtype_name 返回的字符串)应为带引用的对象,但实际上由于该值产生于局部变量中,返回后立即被释放,导致内存访问错误。
  • 处理:测试阶段去掉了第 8 版本的 Protobuf,其他部分一切正常。作者下载了最新版仍存在该问题,未深入分析根因。

Lua 的引入与线程限制

  • 作者尝试用 Lua 做所有事(Lua 脚本 + Lua 库),但发现 Lua 无法在子线程中做 UI 处理
  • 结论:Lua 与 JS 各有优劣——这里属于“退了一次,有可能都是退一次”的折衷方案。

辅助框架设计与使用方式

整体架构

架构共分三层:

  1. 底层(C++ 核心层) :加载游戏、内存操作、数据包拦截与发送、FLASH 支持、hooks、提供 JS 执行环境和数据转换服务。
  2. 中间桥接层(CEF / V8 / 自定义 API) :向 JS 提供底层接口,注册回调;开发者工具(F12)。
  3. 上层开发层(JS + 可选任意后端) :辅助界面、业务逻辑、数据展示、数据包拦截与修改等,风格与前后端(B/S 架构)开发一致。

功能面板与配置

  • 框架界面加载本地 localhost:8080(由后端服务延伸的端口),后端服务内嵌前端页面(由前端构建产物提供)。
  • 配置通过一个 YAML 文件完成(配置量不需要很多),关键配置项包括:
  • command:自动更改指令;
  • 皮/主题类型选择(QSS 主题);
  • 默认请求地址;
  • useCWD:是否使用本地路径加上当前路径(作者初期直接用原版 SWF 测试时未使用 Web 服务方式,设 0 时使用本地路径);
  • tap:取值 0 或 1——0 代表黑夜模式(可启用暗色主题)。

消息类型与通道

  • 通信分两个通道
  • login(登录/校验服务器);
  • data(数据传输)。
  • 上层发数据包时需在 send 时选择相应的通道(如 getRoomlogin,瞬移等走 data)。

核心 API 函数(JS 侧)

作者在 JS 侧通过 V8 扩展为上层提供了一系列封装的函数,大致包括:

  • 通过一个 Command ID 获取对象(如 getObjectByCommandId,内部调用 AppView 的逻辑——返回带 ADF 字段的对象,含大量字段可 console 输出查看)。
  • 通过对象获取字节数组:getDataByObject(obj)——对象拼好后转成字节数组用于发送。
  • send:发送数据包(可选 logindata 通道)。
  • 通过 V8 函数封装将注册回调函数派发到内部数组,在网络事件到达时遍历回调数组逐一声明调用。
  • 回调类型支持 request(请求)与 reply(回复)侧拦截;支持拦截后决定丢弃或修改(dc 字段标记是否需要修改数据包)。
  • 网络数据包经字节流传入后:
  • 当类型判定可转换时,使用 ByteToThree/byteToString 等方法转为字符串展示。
  • 默认展示为“整数类型”字节数组(因部分字段无法判断类型);若开发者确认是字符串,可调用转换方法读取。
  • nicknameroomId 等字段常用此方式处理。

前端工程介绍

  • 前端技术栈:作者使用了 Vue(配合 Vue Router 等),最终将前端编译后嵌入后端。
  • 后端技术栈示例:Python Web 框架;(如 FastAPI)负责处理数据、提供接口。
  • 实际作者以一个小型演示示例(记录游戏登录、房间信息等功能)作为示例来讲解。

核心功能演示与实现逻辑

数据包日志与查看

  • 框架支持抓包:当前端触发游戏内动作(如回家园、瞬移、切图)时,所有经过的数据包(请求和回复)会被截获并展示在日志列表中。
  • 每条数据包可点击“查看详情”:
  • 显示 Command 类型、请求/回复内容、原始字节、字符串解析值等;
  • 如切换房间:客户端发一个 Command(如 304)请求,收到 304 回复;结果显示 mapId=10000(10000 代表家园房间号)、源房间号 382 等。
  • 注意:C++/Socket 层传送的目标房间 ID 只能带有符号整数,导致较大正数展示为负数;其真正值是无符号整数形式(如 331730899)。作者在显示上做了“有符号转正”(UInt→展示为正数)。
  • 协议编号对照:如 196612 对应“改变场景”操作(作者通过代码中定义查得)。

功能示例 1:瞬移

具体实现:

  • 通过 commandID 获取对象(getObjectByCommandId 返回 ADF 对象)。
  • 修改该对象关键字段,如:
  • Oses 字段为目标场景 ID(如 382);
  • 原始地址(初始地图等)设为 13(若回家需设置为 0,因为回家请求可能需要区分好友家园:若想去他人家园可填对应好友家园号,10000 是自家家园)。
  • 对象构造完成后,调用 getDataByObject(obj) 得到字节数组。
  • 通过 send 发送到 data 通道。
  • 效果:视频演示中角色成功瞬移到目标场景。

功能示例 2:虚假房间列表

  • 通过拦截 RoomReply(请求房间范围),获得返回的房间数据。
  • 在回调中修改房间号等字段:如将 room index 改成 9999,将 query 返回的房间 ID 改为 999——实现对房间列表的欺骗性修改(展示层面)。
  • 根据条件:拦截代码中判断若 command == TDRCommand.reply,并且收到数据包类型为 receiveData(收到回复),则将房间号改 999;并设置 dc 字段为 true 表示需要修改数据包,否则视为不修改丢弃。
  • 可借此实现“虚假房间”“修改房间范围”等扩展功能(如只显示 16 个而不是全部房间),亦可用于快速定位与筛选(例:将房间范围改为 16)。
  • 每个房间返回的数据中还包含服务器 IP 地址(以 uint 形式传入),可自行转换展示——每个服务器能开约十几个端口,每个端口代表一个服务器。

功能示例 3:ACL(HTTP 类)请求返回内容篡改

  • 演示:拦截一个 ACL 请求的回复,将返回内容(例如 HTML/XML 文本)替换为空字符串或任意字符串。
  • 替换为空后页面可迅速加载出来(表现为移除阻塞资源);替换为“123”后页面呈现“123”字样输出——证明改动生效。
  • 修改限制:返回内容长度不能超过 maxContent(最大修改长度);若实际需更多空间,框架提供 cancel 与“需要更多数据”等反馈机制。
  • 回调原型(针对 ACL reply 注册的回调函数)传入的参数为五个:
  1. method(POST/GET);
  2. URL;
  3. content(返回内容);
  4. contentLength;
  5. maxModifyLength。
  • 该功能的意义:可修改游戏加载的 XML 清单字段,实现特殊功能;也可通过此机制批量下载很多 SWF(作者当初就是这样下载游戏资源的)。
  • 由于返回包回调是同步回调(同步实现 fil 函数):受 V8 引擎限制(进程与渲染线程不同,且开启了沙箱/隔离),同步回调无法异步处理,只能同步返回。无法实现的场景(需要更多数据、出错等)需借用上述参数反馈。
  • 调试输出:Qt Debug 输出需要借助文件等方式查看,不太便于直接测试,因此该部分作者没有展开演示。

功能示例 4:注册式消息订阅

  • 在 S(上层/脚本初始化)时,先调用所有接口但不对页面做立即修改,而是记录感兴趣的全局字段(如 nicknameuanroomId)。
  • 注册多个回调(提供几个回调接口:请求发过来时回调、收到回复时回调,均传入 message 对象)。
  • 可对特定消息注册多个函数,通过数组管理实现“发布-订阅”模式:
  • 注册(addCallback)→ 存数组;
  • 事件到达 → 遍历数组逐个调用。
  • 演示中,对“HighRoom”(改房间)感兴趣时,在回调中修改 room 为 999 并 dc = true,实现拦截修改。

其他细节功能

  • 获取/打印每个登录游戏时区服的 IP 地址。
  • 好友、会话、防沉迷/时段限制相关逻辑:演示到晚上 11 点后游戏无法登录,连接失败——作者没有深入测试。
  • 提供右键运行 Flash Player 插件的适配(当前路径加载 Flash 308 版本)。

开发流程与扩展方式

第三方开发者如何上手

  • 底层协议和框架由作者维护;第三方开发者只需要具备前端(JS)能力。
  • 辅助功能开发流程 “非常简单”:画界面 + 写 JS,像写前后端一样开发。
  • 作者目前以几个简单的示例模板(含注册回调、数据包读取功能、瞬移与虚假房间功能)为开发者演示了 API 用法和工程结构。
  • 源码将放出(原版资源一并发布),作者鼓励感兴趣的开发者基于模板做二次开发。但未提供具体发布时间与链接(视频中未提及本期对应的具体仓库地址)。

实现方式对比评述

  • 市面已有方案评价:多数基于成熟成品辅助工具研发;但很多是用旧有外挂处理方式,例如在“易语言”这种层级做处理,开发方式落后——与现代前后端开发方式脱节。
  • 本框架优缺点评价:
  • 优点:开发模式现代、数据包全透明、协议已全部解析、可拦截/修改/代发所有数据包。
  • 缺点体积很大(200~500MB),主要原因是需要完整附带 Qt5 依赖、CEF 库、YAML 库、Lua、Protobuf、Flash 播放器(308 版本)等资源;尤其需要完整带上游戏资源时体积更大(带 Plus/原版资源后约数百 MB)。

目标用户

  • 只适合有开发经验、想自己写功能的人;非开发者的普通玩家仍建议使用现成的辅助工具或明确“不是给我这个开发的”。

安全性与限制

Flash 安全背景

  • Flash 插件已经被浏览器厂商严格禁止,最主要原因是“太不安全”。
  • 网络流传的游戏版本存在较大安全隐患。
  • 作者使用 CEF + 独立 Flash 播放器,将运行环境隔离(沙箱/后门模式);提供“后门”来执行 JS 并注入到目标页面(CF 页面)中运行——这类机制存在潜在安全风险,但框架目前局限在作者可控环境中使用。视频中作者强调:“可能需要安全性做得好一点,所有数据处理在我底层完成,上层不需要关心细节”。

框架中尚未完善的部分

  • 会话保持(刷新后状态丢失,需重新登录)。
  • 服务端校验逻辑(演示用的后端接口未加权限校验;作者预告正式公开应会加上)。
  • 界面美化不完整(部分控制面板链接按钮风格与整体不统一)。
  • 夜间模式界面还未完整实现。
  • Flash 最新版本的完整支持与不稳定 bug 仍未彻底排查(如 CEF 异步 I/O 的怪问题)。
  • 体积未优化。
  • 未完成所有 YAML 配置项的图形化配置与管理。
  • 数据包列表(抓包部分)暂未持久化/未做复杂筛选功能。

后期计划与分享预告

作者后续将“回到正轨”,恢复分享漏洞相关知识:

  • 因最近做了较多 CEF 相关工作,可能先讲浏览器漏洞相关内容;
  • 还会继续录一些“优异(运维?)/渗透测试”相关的内容,可能会“漏多一点”。

文中未透露具体时间表和已完成进度。

总结

作者从零完成了对《洛克王国》Flash 游戏的数据包协议逆向、资源破解、底层插件化框架搭建和上层开发体系的示例输出,形成了一套结构清晰、便于第三方扩展的辅助开发工具。项目的技术焦点在于:

  1. C++ 负责所有底层(含 Flash 加载及与 CEF 兼容性适配);
  2. 上层通过 JS 自由开发,完成所有逻辑和界面;
  3. 网络层全协议(三种类型、600+ 条)解析完成,做到可拦截、可修改、可转发;
  4. 因个人精力与时间有限,缺失大量打磨;且因配套资源体积大,不适合轻量分发,其定位偏“开发者自用/二次开发基座”。