文件拆解器
只负责无脑搬运,程序风险自行承担。
解压工具下载
用法:
1.如果你是64位,把wowb-64.exe改名成别的(例如wowb-642.exe)
2.打开wowb.exe
3.运行extractor.exe
4.选择wowb.exe进程
5.选择输出目录
6.选择文件列表(包里附带,由TOM_RUS提供)
7.选择DLL的存放目录(如果你原样解压,不用动)
8.单击“Launch”按钮
9.等
10.耐心等
11.等差不多两个小时
12.??
13.完活
CASC (内容可寻存储容器) 文件系统
德拉诺之王 Alpha, Build 6.0.1.18125
1.2版
允许无限制地发布和复制这份说明文档,只要没有修改。允许自由地引用于其他作品,只要声明了引用来源和作者。
0) 简介CASC是目前暴雪在《风暴英雄》和《魔兽世界:德拉诺之王》Alpha版本中采用的新文件格式。
根据说明,它比之前使用的MPQ格式功能更强大,更轻量。截至目前,新格式完全没有加密能力,而且只支持一种文件压缩算法。那些绝不可以被修改的重要文件(例如地图文件)的正确性,依靠位于根目录下的一种叫“signaturefile”的文件来保证。似乎以后再也没有办法获取客户端包含的全部文件的文件名了,MPQ包含一个“(listfile)”用纯文本给出所有文件名,而CASC似乎没有。
在我的分析中,仍有几处含义不明的值。利用我所发现的知识,你应该能够从压缩档中定位并提取任何已经完全下载下来的文件。
我的研究范围不涵盖任何按需下载或部分下载的文件,它们可能会引入一些难以理解的问题。另外目前只涵盖了'data/data/'目录下的文件。我还没搞明白'data/config/'和'data/indices/'下的文件是干什么用的,不过没有它们照样可以提取游戏文件。
欢迎任何反馈,也希望我的发现能够帮助其他人解开剩下的谜团。
0.1) 术语
[LE]:给定数据按小端对齐存储。
[BE]:给定数据按大端对齐存储。
译注:32位数“0x12345678”按[LE]存储会存为“0x78 0x56 0x34 0x12”;按[BE]存储会存为“0x12 0x34 0x56 0x78”。
0.2) BlizzHash
除MD5以外,还需要用到一种Bob Jenkins的散列算法,后文称作BlizzHash。Hash值由A、B两部分组成,每部分为4字节;有时两部分都会用到,有时只用一个。数据按每块12字节进行散列,但余下不足一块的数据也会参与散列。实际实现请参照'BlizzHash.cpp'。
译注:
其中有一个宏定义HASH_BLOCK_SIZE 12意即按12字节分块。
请注意在生成每个Hash值之前都需要将HashA和HashB都初始化为0
1) data.XXX 文件
1.1) 概述
所有 data.XXX 文件(后文称作“data文件”)是单纯的文件容器。它们只包含纯文件内容,没有任何的索引信息。所有包含在内的文件按照有序的二进制块存储,每一块有一个很短的首部(30字节)。由于技术所限(参见IDX文件编址格式),任何data文件都不能超过2^30 = 1,073,741,824字节。然而,最多可以有2^10 = 1,024个data文件并存,所以整个系统可以寻址超过1TiB的压缩数据(含额外开销)。
1.2) 文件格式
1.2.1) 整体格式
1.2.2) [块]格式
- 16 字节 - MD5校验和(不确定是校验谁,也许是首部?)
- 4 字节 - 整块的大小(包括前面的校验和),以字节为单位[LE]
- 10 字节 - 未知
- [数据] - 长度为整块的大小减去30字节
2) BLTE 文件
2.1) 概述
BLTE文件是(目前)data文件中唯一包含的文件类型。它包含了实际的游戏文件,可以分簇,每一簇独立地压缩(也许还能独立地下载)。
2.2) 文件格式
2.2.1) 整体格式
- 4 字节 - 标头“BLTE”
- 4 字节 - 压缩数据偏移,以字节为单位[BE]
- if(压缩数据偏移 > 0)
{- 2 字节 - 未知,猜测是[BE]
- 2 字节 - 簇数量[BE]
- for(簇数量)
{- 4 字节 - 压缩簇大小,以字节为单位[BE]
- 4 字节 - 解压后簇大小,以字节为单位[BE]
- 16 字节 - 簇MD5校验和(应该是按压缩后的簇,我觉得)
} - for(簇数量)
{}
} - else
{}
2.2.2) [压缩数据块]格式
- 1 字节 - [数据]的压缩类型(目前用'N'表示未压缩,'Z'表示用Deflate算法(ZLib))
- [数据] - 长度为压缩后大小减1字节
译注:ZLib需要拿源码自己编译一遍才能用。
3) *.idx 文件
3.1) 概述
IDX文件将前9字节的MD5‘文件键’(后详)与所在的data文件编号(data.XXX)和在该文件内指向该[块]起始位置的字节偏移量建立对应关系。IDX文件由以下两块连在一起写作十六进制形式作为文件名:
- 1 字节 - 文件编号(总是在0x00 .. 0x0F之间)
- 4 字节 - 版本号[LE]
在更新时,老版本会被保留,一旦发生数据污染就能恢复数据。对同一个文件编号,只要装载版本号最高的IDX文件就足够了;而对同一个版本号,每一个文件编号的IDX文件都必须装载。
3.2) 文件格式
3.2.1) 整体格式
- 首部1:
- 4 字节 - 首部2的长度(按字节)[LE]
- 4 字节 - 首部2的BlizzHash校验和(只要A部分)[LE]
- [填充] - 全部填0x00直到坐标(8 + 首部2的长度 + 0x0F) & 0xFFFFFFF0
- 首部2:
- 4 字节 - 数据长度(按字节)[LE]
- 4 字节 - 数据的BlizzHash校验和(只要A部分)[LE]
(数据按18字节分块散列!)
- 数据:
- for(数据长度 / 18)
{} - [填充] - 全部填0x00直到坐标(数据长度 + 0x0FFF) & 0xFFFFF000
- [未知]
译注:首部2应该还包含了其他信息,我尝试看了几个,后面都有一个32位数“0”和32位数“4”[LE],总长度为16字节,但作者没有说明。填充存在的目的应该是将数据块的起始位置按4KiB在文件内对齐,加快速度——猜测WoW是按4KiB/次读取磁盘文件的,等同于NTFS默认的磁盘簇大小。
3.2.2) [块]格式
- 9 字节 - 文件键的前9字节
- 1 字节 - 索引信息的高字节
- 4 字节 - 索引信息的低字节[BE]
- 4 字节 - 文件大小,以字节为单位[LE]
索引信息按下面的方式计算后可以得到编号和偏移:
- data文件编号 = (高字节 << 2) | ((低字节 & 0xC0000000) >> 30)
- data文件偏移 = (低字节 & 0x3FFFFFFF)
译注:IDX文件用于定位BLTE在哪一个data文件的哪一个位置上。读取时可以把索引信息的高字节和低字节看作一个整体,[BE],等到运算时再切分开。
4) data文件中包含的特殊文件
4.1) 概述
在data文件中,有4个特殊的文件,用于文件系统管理,而非普通的游戏文件。因此它们没有被IDX文件索引,而是依据它们在data文件中的MD5校验和,由Build配置文件(后详)予以索引。
译注:这几个特殊文件,同样装在BLTE里,要从BLTE里解出来才是这些文件。
4.2) "encoding"文件
4.2.1) 概述
给定一个文件内容的MD5散列值,"encoding"可以确定其文件键。文件键通过IDX文件就可以找出实际文件内容的存放位置。文件键可能也是一个MD5散列,但我还没找出它究竟散列了什么东西。不过,只是出于单纯的提取游戏文件的目的,这没什么关系。
从data文件和BLTE中提取出来之后,它的格式如下所述。
4.2.2) 文件格式
- 首部:
- 2 字节 - 语言(?)'EN'
- 1 字节 - 未知
- 1 字节 - 未知
- 1 字节 - 未知
- 2 字节 - 未知,可能是[BE]
- 2 字节 - 未知,可能是[BE]
- 4 字节 - Hash表大小[BE]
- 4 字节 - 未知,可能是[BE]
- 1 字节 - 未知
- 4 字节 - Hash表偏移,以字节为单位[BE]
- 未知:
- 一组纯文本,以零结尾的ASCII字串,直到首部结束之后[Hash表偏移]个字节处。
- Hash表校验和块:
- for(Hash表大小)
{- 16 字节 - 后面的Hash表块中第一个入口的文件内容MD5
- 16 字节 - MD5校验和(也许是校验后面Hash表块的?)
}
- Hash表块:
- for(Hash表大小)
{- while( 2个字节非零 )
{- 4 字节 - 文件大小,以字节为单位[BE]
- 16 字节 - 文件内容MD5
- 16 字节 - 文件键
} - 28 字节 - 在最后一个入口结束后填充0x00
}
译注:
这一段可能不好理解,作者没有解释入口的概念,我简单解释一下。
这个while表示读两个字节,如果不是零,就再读后面4+16+16个字节——这36个字节合在一起称为一个“入口”。每一个Hash表项可能有多个入口。
每一个Hash表项的第一个入口的“文件内容MD5”这一段(也就是第一个入口的[4:19],整个表项的[6:21])会写在前面“Hash表校验和块”里面。
如果while处读到的两个字节都是零,说明该表项已经结束,在其后会有28个填充零。
4.3) "root"文件
4.3.1) 概述
"root"将一个游戏文件完整文件名的BlizzHash与该文件的内容的MD5校验和关联起来。依据内容的MD5校验和可以在"encoding"中获取文件键。"root"是由单纯的许多数据块组成,直到文件结束。从data文件和BLTE中提取出来后,它的格式如下所述。
4.3.2) 文件格式
4.3.2.1) 整体格式
- [数据块] [数据块] [数据块] .... [数据块]
4.3.3.2) [数据块]格式
- 首部:
- 4 字节 - Root入口数量[LE]
- 4 字节 - 未知,可能是[LE]
- 4 字节 - 未知,可能是[LE]
- 未知:
- 数据:
- for(Root入口数量)
{- 16 字节 - 文件内容MD5
- 4 字节 - 文件全名的BlizzHash(B)[LE]
- 4 字节 - 文件全名的BlizzHash(A)[LE]
}
4.4) "download"文件
4.4.1) 概述
这是data文件中所含四个特殊文件中的一个。
4.5) "install"文件
4.5.1) 概述
这是data文件中所含四个特殊文件中的一个。
5) Build配置文件
5.1) 概述
这些文件位于'data/config/'。它们的文件名就是一段MD5散列,但我还不知道散列了什么。
它们存放于一种目录结构中,以其MD5的前两字节和次前两字节作为目录名。例如一个名为'806f4fd265de05a9b328310fcc42eed0'的Build配置文件可以在'data/config/80/6f/'目录下找到。
这些文件是一种格式类似ini的纯文本文件,包含了客户端一个Build的信息。它们遵循一种类似'变量名 = 变量值'的格式,'#'用于注释。目前指定了这些变量:
5.2) 指定变量
变量名 | 信息 | 示例 | build-name | Build名字 | 'WOW-18125patch6.0.1' | build-playbuild-installer | 使用的安装程序 | 'ngdptool_casc2' | build-product | 产品名 | 'WoW' | build-uid | Build的UID | 'wow_beta' | download | "download"文件的MD5散列 | encoding | "encoding"文件的MD5散列 | install | "install"文件的MD5散列 | root | "root"文件的MD5散列 |
请注意对这四个特殊文件,可能会给出多个MD5散列值。这时,最后一个给出的值可能是正在使用的。
6) CDN(内容分布网络)配置文件
6.1) 概述
这个文件位于'data/config/'而且与5)中描述的Build配置文件具有相同的命名和存放规则。它们也有相同的文件格式。CDN配置文件包含了对所有可用的Build配置文件、档案组、档案和位于'data/indices'的补丁档案的引用。
6.2) 指定变量
变量名 | 信息 | archive-group | 位于'data/indices/'的档案组文件 | archives | 位于'data/indices/'的所有档案文件,以一个空格分隔 | builds | 位于'data/config/'的所有Build配置文件,以一个空格分隔 | patch-archives | 位于'data/indices/'的所有补丁档案文件,以一个空格分隔 |
7) 从CASC文件系统读取内容的处理流程
7.1) 初始化
- - 加载CDN配置文件并找到要用的Build配置文件
- - 加载Build配置文件
- - 加载所有IDX文件并将数据存储于一个关联容器中:
(文件键的前9字节 -> 索引信息) - - 利用从Build配置文件中找到的MD5,从data文件中定位并提取"encoding"文件
- - 加载encoding文件并将数据存储于一个关联容器中:
(文件内容MD5 -> 文件键) - - 利用从Build配置文件中找到的MD5,从data文件中定位并提取"root"文件
- - 加载root文件并将数据存储于一个关联容器中:
(完整文件名的BlizzHash -> 文件内容MD5)
** 注意单个BlizzHash可能会对应多个root入口,但其中只有一个是有效的! **
** 暂时还不知道如何确定哪一个是有效的 **
7.2) 定位并读取文件
- - 将文件名转换为全大写,并将'/'替换为'\'
- - 用文件名生成BlizzHash
- - 用BlizzHash找到正确的root入口(或者干脆把找到的全试一遍..)
- - 用root入口中给出的文件内容MD5,在encoding文件里查找文件键
- - 用文件键,在IDX文件里查找索引信息
- - 用索引信息,定位并提取该文件的BLTE
- - 从BLTE中提取文件
8) Changelog- v1.0
- v1.1
- - FileTable更名为"encoding"文件
- - Manifest文件更名为"root"文件
- - 指出BlizzHash实际上是Bob Jenkin的散列
- - 添加关于"download"和"install"文件的信息
- v1.2
译注:TOM_RUS指出,现在最大的问题,是无法直接定位root文件,必须依靠一个MD5从海量的data文件里逐一寻找,导致加载速度奇慢无比。要想得到一份完整的文件列表,目前我们只有两种办法:暴力遍历,或者从暴雪总部偷出来。
你必须知道要提取的文件的文件名是什么,才能提取到它。目前来看,CASC不会保存文件名信息,而这正是新文件系统的设计意图。
|