FiveM

从进服状态到本地目录:FiveM 资源整理管线

粗略整理 CK 的 dump 工具如何识别连接、读取资源清单、展开 RPF、覆盖 stream,并保留可追查的失败证据。

dump 目录不是一个只负责下载的单文件脚本。它由 Node.js 主入口、Python 连接识别、RPF 读取器、资源后处理 worker 和若干诊断脚本组成,目标是把一次 FiveM 连接中的资源信息整理成可检查的本地目录。

这套工具只适用于资源所有者、服务器管理员或已经取得明确授权的研究场景。本文只整理工程结构和验证边界,不提供授权绕过、密钥材料或受保护资源的解密步骤。

主流程做了什么

主入口是 index.js,一次完整运行大致分为八个阶段:

  1. 读取 config.json,确定服务器地址、下载范围和下载源优先级。
  2. 规范化完整 URL、IP:PORT、Join Code 或当前进服状态。
  3. 取得当前连接上下文,并向目标服务器确认它是否可用于 getConfiguration。
  4. 输出资源名、普通文件数量和 stream 文件数量。
  5. 按完整资源名或资源名前缀缩小处理范围。
  6. 下载并展开 resource.rpf,再补齐普通文件与 stream 文件。
  7. 把原始目录交给独立后处理进程,按目录形态分派 worker。
  8. 输出原始目录、整理后目录、失败统计和必要的调试文件。

这种拆分让连接发现、网络下载、归档解析和文件后处理彼此独立。某一步失败时,不必从头猜测整个链路。

连接地址与当前会话

地址入口集中在 normalize_http_server_url、get_cfx_join_code、resolve_cfx_join_url 和 resolve_config_server_url。它们负责把不同形式的连接地址转换成服务器 HTTP 入口。

当 Join Code 目录接口没有返回 endpoint,主流程还会尝试从当前 FiveM 进服状态恢复服务器地址。这个回退很重要,因为有效 Join Code 也可能暂时无法从目录接口直接解析。

get_token.py 与 get_token_core.py 负责从本机当前 FiveM 进程中筛选候选连接上下文,再由目标服务器响应确认候选是否有效。主流程设置了时间、扫描量和候选数量上限,并且日志只显示掩码,不直接打印完整值。

资源清单与范围控制

get_configuration_once 请求服务器 /client 的 getConfiguration,拿到资源列表后由 print_resource_list 输出:

  • 资源名称
  • resource.files 普通文件数量
  • streamFiles 流文件数量

如果列表为空,save_empty_resource_debug 会保存实际响应,方便判断是连接上下文失效、服务器结构变化,还是本次响应确实没有资源。

资源筛选同时支持完整名称和前缀。大型服务器可以先处理一个资源或一组同前缀资源,不必每次硬跑全量目录。

下载回退与失败保留

下载层会同时构造服务器 /files 地址和配置中返回的 fileServer 或 CDN 地址。use_server_for_downloads 只改变优先顺序,不会取消备用来源。

网络层还处理了这些细节:

  • 对路径的每个片段单独进行 URL 编码。
  • 兼容字符串哈希和对象哈希两种清单结构。
  • 403 或 404 时切换候选下载源。
  • 对暂时性错误执行有限次数重试。
  • 下载完成但后处理失败时保留原始文件,不静默删除证据。

RPF 与普通文件

每个资源优先处理 resource.rpf。ResourceDecryptor 把传输结果交给 rpf.js,后者检查 RPF2 头、目录表、条目表和名称表,再递归写入原始资源目录。

成功展开后会生成 .rpf-extracted.json,记录资源名、展开文件数和来源。下一次运行看到这个标记会跳过重复展开。中间归档以 __resource.rpf 保留,便于后续核对。

当前 rpf.js 只接受未加密目录表的 RPF2。它不是通用 RPF7 解析器,这一点不能从“成功打开一个 RPF”扩大成对所有 Rockstar 归档格式的支持。

stream 与目录后处理

download_all_files 开启后,主流程会补齐 resource.files 中除 resource.rpf 外的条目,并处理 streamFiles。stream 下载固定使用较低并发,已有文件会直接跳过,以减少大资源目录中的连接中断。

下载完成后,decrypt-eup-stream.js 会把目录分成三类:

  • 根目录存在 .fxap 控制文件的单资源。
  • 容器目录下包含多个独立资源。
  • 没有控制文件的 stream-only 或普通文件目录。

带控制文件和 stream-only 两类任务使用不同 worker。普通文件直接复制,受保护文件只在已有合法授权上下文时进入后续处理。输出会分别统计复制、处理、失败、缺少资源 ID 和缺少授权元数据的数量。

Lua、RSC 与原生辅助模块

底层处理器会按文件类型分路:Lua bytecode 交给 Tools/unluac54.jar,常见 stream 扩展名交给资源文件处理分支,其他文件走通用输出路径。反编译失败时会保留 bytecode、反汇编或错误产物,因此结果不是“保证还原成原始源码”。

Tools/DecryptBin 中还有本地原生辅助模块和对应 C++ 源码。它属于授权范围内的内部处理依赖,公开文章不展开其密钥输入、常量和算法细节。

当前验证能说明什么

这个目录当前有三层不同强度的确认:

层次 当前确认方式 不能据此声称的结论
连接 目标服务器接受 getConfiguration 不代表任意服务器都能使用同一连接上下文
RPF RPF2 头、目录表和条目读取成功 不代表支持全部 RPF 版本
Lua 与 RSC 检查 Lua、RSC7、RSC8 的文件签名 不代表模型几何、纹理、碰撞或运行时行为完整

仓库中没有完整的 RSC 页表验证器,也没有内置 FiveM 运行时回归。最终资产是否可用,仍需要在合法测试环境中加载验证。

仍需整理的地方

  • Lua 输出实际依赖 Java,但现有环境说明没有完整列出 Java。
  • 代理分支引用可选依赖,默认关闭,开启前需要补齐依赖检查。
  • package.json 中存在当前主链没有直接使用的历史依赖。
  • 下载保持补丁仍是实验草稿,不属于当前主流程。
  • 第三方授权数据路径不应进入正式发布流程,后续应删除或隔离。

这套管线最有价值的不是“把文件下载下来”,而是把每一步的输入、输出、跳过原因和验证强度留在明确位置。排错时可以直接回到实际失败层,而不是把网络、归档和资源格式问题混在一起。