近日,一位技术爱好者在其个人博客中详细披露了如何通过逆向工程手段,使用 Ruby 语言解析《F1 2020》《尘埃拉力赛2.0》等游戏开发商 Codemasters 所使用的 BIGF 存档格式。该研究不仅为游戏 Mod 开发者打开了新的大门,也揭示了大型游戏工作室在数据打包方面的内部实现细节。
一、BIGF 格式:被遗忘的档案柜
BIGF 是 Codemasters 在多个赛车游戏中采用的自定义存档格式,其名称可能源自“Big File”(大文件)的缩写。与常见的 ZIP、PAK 等通用压缩格式不同,BIGF 是一种纯粹的归档格式——它仅将多个文件(如纹理、模型、音频)连续拼接存储,并附加一个紧凑的索引表,记录每个文件的偏移量、大小和名称。
根据逆向分析,一个标准的 BIGF 文件结构如下:
- 文件头(12 字节):包含魔数
BIGF(4 字节)、版本号(4 字节,通常为 2)、文件数量(4 字节)。 - 文件条目表:每个条目占 60 字节,包括文件名(48 字节,以空字符填充)、文件偏移量(8 字节)、文件大小(4 字节)。
- 数据区:所有文件按顺序连续存储,无额外对齐或压缩。
这种设计在 2000 年代早期非常流行,其优势在于索引简单、读取快速,但缺点也很明显:无法压缩、无法单独更新,且文件名有长度限制。
二、逆向工程:从二进制到 Ruby 代码
这位技术爱好者(以下简称“作者”)在分析《F1 2020》的更新包时,注意到其 .bigf 文件内部似乎存储了多个独立的资源文件。由于缺乏官方文档,他决定采用经典的二进制逆向流程:
- 十六进制查看器初探:使用
xxd或 HxD 打开文件,观察到开头的BIGF魔数和紧随其后的两个 32 位整数,初步推断为版本号和文件数。 - 模式识别:在文件的不同位置发现以
00000000填充的区域,进一步分析确认这些是文件名与数据之间的对齐空白。 - 偏移量验证:通过计算第一个文件的偏移量(从索引表后开始),并与文件头中的文件数量相乘,验证了索引表的精确长度。
- 编写 Ruby 脚本来解析:
class BigfArchive
def initialize(file_path)
@data = File.binread(file_path)
parse_header
parse_entries
end
private
def parse_header
magic = @data[0, 4]
raise 'Not a BIGF file' unless magic == 'BIGF'
@version = @data[4, 4].unpack1('V') # 小端存放
@file_count = @data[8, 4].unpack1('V')
end
def parse_entries
offset = 12
@entries = @file_count.times.map do
name = @data[offset, 48].delete("\x00").strip
file_offset = @data[offset + 48, 8].unpack1('Q')
file_size = @data[offset + 56, 4].unpack1('V')
offset += 60
{ name: name, offset: file_offset, size: file_size }
end
end
def extract_all(path = 'extracted')
Dir.mkdir(path) unless Dir.exist?(path)
@entries.each do |entry|
content = @data[entry[:offset], entry[:size]]
File.binwrite("#{path}/#{entry[:name]}", content)
puts "Extracted #{entry[:name]}"
end
end
end
这段代码仅约 40 行,却能够完整无误地解包任意一个 BIGF 存档,充分体现了 Ruby 在二进制数据处理上的灵活性。作者还特别提到,使用 unpack 方法和 Q(64 位无符号整数)、V(32 位小端无符号整数)等模式,可以高效地从字节序列中提取结构化数据。
三、意义与影响:从社区实用到学术价值
这项逆向工程工作对游戏 Mod 社区具有直接意义。此前,要修改《F1 系列》或《尘埃系列》的车辆涂装、HUD 元素或音频文件,玩家往往需要借助第三方闭源工具,且这些工具常常滞后于游戏更新。而有了开源的 Ruby 解析器,任何人都可以自行解包、替换资源并重新打包(只要实现反向写入逻辑),完全不受原公司支持周期的影响。
从技术角度看,BIGF 格式的简单性也反映出早期游戏开发中的“实用主义”哲学——在磁盘空间和内存都极为有限的年代,无需压缩的归档格式能够保证最低的加载延迟。Codemasters 一直沿用至今,甚至在一些新作中仍能看到其身影,这本身就值得技术史研究者注意。
四、结语
“逆向工程不是破解,而是学习。”作者在文末如此总结。通过 Ruby 这把瑞士军刀,我们得以窥见一个主流游戏工作室的存档格式设计思路。对于希望深入理解游戏文件结构或从事 Mod 开发的读者,这篇教程无疑是一份入门级的宝典。随着更多爱好者加入这类逆向工作,或许未来我们能期待一个由社区维护的、跨游戏的统一资源管理工具。
(本文基于公开技术博客内容编译整理,所有代码仅供学习研究使用,请遵守相关游戏用户协议。)