【问题标题】:Identifying DEFLATE Algorithm Variant Being Used in Proprietary File Format识别在专有文件格式中使用的 DEFLATE 算法变体
【发布时间】:2016-07-08 22:05:44
【问题描述】:

免责声明:这个问题需要对 DEFLATE 算法有很好的了解。

我希望我可以征求一些想法,以确定在特定文件格式中使用的压缩算法。这是我的应用程序需要支持的遗留专有格式,因此我们正在尝试对其进行逆向工程。 (去原始创作者不是一个选择,原因我不会进入)。

我非常接近破解它,但我觉得我生活在 Xeno 的悖论中,因为我似乎每天都在接近终点线的一半,但从未到达!

这是我目前所知道的:

它肯定使用了与 DEFLATE 算法极为相似的东西。相似之处 -

  • 压缩数据由规范的霍夫曼代码表示 (通常以 000 开头,但我不确定是否总是 案子)。
  • 数据前面(我相信立即)有一个标题表 它标识每个实际代码的位长度。像 DEFLATE,该表还包含规范的霍夫曼代码 (从 0 或 00 开始)。这些代码提供的位长度 0-255+ 字母表中的每个字符加上任何距离代码 可能会用到。
  • 最后,再次像 DEFLATE 一样,带有 主要代码的位长度也在前面(我认为立即) 由一系列 3 位代码用于派生头表代码 (我将其称为“前标头”)。

到此为止,相似之处似乎已经结束。

pre-header 中的 3 位代码不会按照 DEFLATE 指定的 16、17、18、0、8 ... 最佳顺序出现,而是按顺序排列,如 6 7 8 9 ....

另一个区别是每个 3 位代码不一定是字面位长度。例如,这是一个我已经基本破译的标题(我有 99.99% 的把握它是正确的):

00000001011 100 010 110 010 010 011 010 110 101 100 011 010 010 011 100 010 111
            *0*     skA                 *3* *4* *5* *6* *7* *8* *9* skB

忽略未标记的位,这将导致以下代码表:

00       7-bits
01       8-bits
100      6-bits
101      9-bits
1100     0-bits (skip code)
1101     skA = skip 3 + value of next 4 bits
1110     5-bits
11110    4-bits
111110   skB = skip 11? + value of next 9 bits
111111   3-bits

最明显的问题是头表中有额外的未使用的位长度。而且,事实上,它们根本不可用,因为不能有任何额外的 2 位或 3 位代码,例如,代码是规范的(对吗?)。

作者还使用了 16+ 的非标准代码。他们似乎根本不使用复制代码(DEFLATE 中的 16);主标头都有大量相同长度的代码字符串(非常低效......),并且跳过代码分别使用接下来的 4 和 9 位来确定跳过的数量,而不是 DEFLATE 中的 3 和 7。

另一个关键区别在于标头的第一个位。在 DEFLATE 中,第一位是 HLIT(5)、HDIST(5) 和 HCLEN(4)。如果我使用 LSB 打包以这种方式解释上述标头,我会得到 HLIT = 257(正确)、HDIST = 21(不确定是否正确)和 HCLEN = 7(绝对不正确)。如果我改用 MSB 打包,我会得到 HLIT=257、HDIST = 6(更可能正确)和 HCLEN = 16(看起来正确)。但是,我认为实际上并不打算在前缀中使用 14 位,因为我似乎需要“100”(见上文)作为 0 位(跳过)代码的位数。在其他示例中,第 10-13 位似乎与预报头的长度根本不相关。

谈到其他示例,并非每个文件都遵循相同的标题格式。这是另一个标题:

00000001000 100 100 110 011 010 111 010 111 011 101 010 110 100 011 101 000 100 011

在第二个示例中,我再次碰巧知道标题的代码表是:

0         8-bits
10        7-bits
110       6-bits
11100     skA
11101     5-bits
111100    0-bits (skip)
111101    skB
111110    9-bits
1111110   3-bits
1111111   4-bits

但是,如您所见,许多必需的代码长度根本不在标头中。例如,没有“001”来表示 8 位代码,它们甚至不接近按顺序排列(既不是连续的,也不是最优的 16、17、18...)。

然而,如果我们将位左移 1:

                           skA                 *0* *5* *6* *7* *8* *9*
0000000100 010 010 011 001 101 011 101 011 101 110 101 011 010 001 110 100 010 001 1

这要好得多,但我们仍然无法正确推导出 skB (110) 或 3 或 4 (111) 的代码。再移动一点并不能改善这种情况。

顺便说一句,如果您想知道我如何确信我知道这两个示例中的代码表,答案是大量艰苦的逆向工程,即查看文件中略有不同或具有可辨别模式的位,并推导正在使用的规范代码表。这些代码表肯定是 99+% 正确的。

总而言之,我们似乎有一个非常接近的 DEFLATE 变体,但出于莫名其妙的原因,它使用了某种非标准的预标头。当然,我被绊倒的地方是确定哪些预标头位对应于主标头的代码位长度。如果我有这个,一切都会水到渠成。

我还有几个可以发布的其他示例,但与其要求人们为我进行模式匹配,我真正祈祷的是有人会识别出正在使用的算法并能够指出我使用的算法.我发现作者不太可能,而不是使用现有的标准,会从头开始编写自己的算法,这与 DEFLATE 99% 相似,但随后仅稍微更改了前标头结构。这没有道理;如果他们只是想混淆数据以阻止我正在尝试做的事情,那么有更简单和更有效的方法。

顺便说一句,该软件的历史可以追溯到 90 年代末、2000 年代初,因此请考虑当时的情况。这不是“中间派”或任何新的和疯狂的东西。这是一个古老的东西,可能是模糊的。我猜想当时在一些半流行的图书馆中使用了一些 DEFLATE 的变体,但我没有太多运气找到关于任何实际上不是 DEFLATE 的信息。

非常感谢您的任何意见。

彼得

PS - 根据要求,这里是帖子中第一个示例的完整数据块。我不知道它是否会有很大用处,但是就这样吧。顺便说一句,前四个字节是未压缩的输出大小。第五个字节开始预头。

B0 01 00 00 01 71 64 9A D6 34 9C 5F C0 A8 B6 D4 D0 76 6E 7A 57 92 80 00 54 51 16 A1 68 AA AA EC B9 8E 22 B6 42 48 48 10 9C 11 FE 10 84 A1 7E 36 74 73 7E D4 90 06 94 73 CA 61 7C C8 E6 4D D8 D9 DA 9D B7 B8 65 35 50 3E 85 B0 46 46 B7 DB 7D 1C 14 3E F4 69 53 A9 56 B5 7B 1F 8E 1B 3C 5C 76 B9 2D F2 F3 7E 79 EE 5D FD 7E CB 64 B7 8A F7 47 4F 57 5F 67 6F 77 7F 87 8F 97 9D FF 4F 5F 62 DA 51 AF E2 EC 60 65 A6 F0 B8 EE 2C 6F 64 7D 39 73 41 EE 21 CF 16 88 F4 C9 FD D5 AF FC 53 89 62 0E 34 79 A1 77 06 3A A6 C4 06 98 9F 36 D3 A0 F1 43 93 2B 4C 9A 73 B5 01 6D 97 07 C0 57 97 D3 19 C9 23 29 C3 A8 E8 1C 4D 3E 0C 24 E5 93 7C D8 5C 39 58 B7 14 9F 02 53 93 9C D8 84 1E B7 5B 3B 47 72 E9 D1 B6 75 0E CD 23 5D F6 4D 65 8B E4 5F 59 53 DF 38 D3 09 C4 EB CF 57 52 61 C4 BA 93 DE 48 F7 34 B7 2D 0B 20 B8 60 60 0C 86 83 63 08 70 3A 31 0C 61 E1 90 3E 12 32 AA 8F A8 26 61 00 57 D4 19 C4 43 40 8C 69 1C 22 C8 E2 1C 62 D0 E4 16 CB 76 50 8B 04 0D F1 44 52 14 C5 41 54 56 15 C5 81 CA 39 91 EC 8B C8 F5 29 EA 70 45 84 48 8D 48 A2 85 8A 5C 9A AE CC FF E8

2015 年 7 月 11 日编辑

我已经设法破译了相当多的额外信息。该算法肯定是使用 LZ77 和 Huffman 编码。长度代码和额外位似乎都与 Deflate 中使用的匹配。

我还能够了解有关预标题的更多详细信息。它的结构如下:

                     HLEN  0  SkS SkL ??  3   4   5   6   7   8   9  HLIT
00000 00101110 001 0 1100 100 100 110 10 110 101 100 011 010 010 011 100010111

HLEN = the last bit-length in the pre-header - 3 (e.g. 1100 (12) means 9 is the last bit-length code)
HLIT = the number of literal codes in the main dictionary
SkS = "skip short" - skips a # of codes determined by the next 4-bits
SkL = "skip long" - skips a # of codes determined by the next 9-bits
0 - 9 = the number of bits in the dictionary codes for the respective bit lengths

我仍然无法破译的未标记位。此外,我现在看到的是,前标头代码本身似乎有一些额外的位(注意上面的 SkL 和 3 之间的 ??)。它们并不都是直接的 3 位代码。

因此,现在唯一缺少的基本信息是:

  • 如何解析预报头中的额外位等;和
  • 文字代码后面有多少个距离代码

如果我有这些信息,我实际上可以通过手动提供代码长度字典以及正确数量的文字与距离代码来将剩余数据提供给 zlib。此标题之后的所有内容都遵循 DEFLATE 的字母。

这里还有一些示例标头,其中包含位长度代码以及文字和长度代码的数量。请注意,在每一项中,我都能够对答案进行逆向工程,但我仍然无法将未破译的位与这些统计数据相匹配。

Sample 1
(273 literals, 35 length, 308 total)
????? ???????? ??? ? HLEN  0  SkS SkL   ??  3  ?  4  ?  5   6   7   8   9       HLIT
00000 00100010 010 0 1100 110 101 110   10 111 0 111 0 101 011 010 001 110      100010001

Sample 2
(325 literal, 23 length, 348 total)
????? ???????? ??? ? HLEN  0  SkS SkL   ??  3   4   5   6   7   8   9           HLIT
00000 00110110 001 0 1100 101 101 110   10 110 000 101 000 011 010 001          101000101

Sample 3
(317 literal, 23 length, 340 total)
????? ???????? ??? ? HLEN  0  SkS SkL   ???  4   5  ?  6   7   8   9            HLIT
00000 01000100 111 0 1100 000 101 111   011 110 111 0 100 011 010 001           100111101

Sample 4
(279 literals, 18 length, 297 total)
????? ???????? ??? ? HLEN  0  SkS SkL   ??  3   4   5   6   7   8   9           HLIT
00000 00101110 001 0 1100 100 100 110   10 110 101 100 011 010 010 011          100010111

Sample 5
(258 literals, 12 length, 270 total)
????? ???????? ??? ? HLEN  0  SkS SkL   ??  2   3   4                           HLIT
00000 00000010 000 0 0111 011 000 011   01 010 000 001                          100000010

我仍然希望有人以前见过这样的非标准 DEFLATE 样式的标题。或者您可能会看到我看不到的模式...非常感谢您提供进一步的意见。

【问题讨论】:

  • 请提供一个完整的压缩数据流示例。
  • 老实说,这听起来像是一场大乱斗。但我认为,如果您至少列出您已经排除的文件格式,您将更有可能获得帮助。 (Have you checked all of these?)
  • 马克 - 我会更新帖子谢谢。
  • squeamish - 几乎不是野鹅追逐。然而,该格式是专有的并且特定于应用程序,因此除了原始软件之外,没有任何程序可以简单地对其进行解码。这显然是一种 DEFLATE 风格的算法,但我已经破译了其中的 99% 以上。
  • 所以你只有压缩数据,没有纯数据?

标签: algorithm compression reverse-engineering huffman-code deflate


【解决方案1】:

好吧,我终于设法完全破解它。它确实使用了 LZ77 和 Huffman 编码的实现,但非常类似于非标准的 DEFLATE 方法来存储和导出代码。

事实证明,前标头代码本身是固定字典 Huffman 代码,而不是字面位长度。找出距离代码同样棘手,因为与 DEFLATE 不同的是,它们没有使用与文字相同的位长代码,而是使用另一个固定霍夫曼字典。

对于任何感兴趣的人来说,显然存在使用 DEFLATE 衍生工具的旧文件格式。他们可以有决心进行逆向工程。在这种情况下,我可能总共花费了大约 100 个小时,其中大部分时间是从已知的解压缩样本中手动重建压缩数据以找到代码模式。一旦我足够了解他们正在做什么来自动化该过程,我就能够制作几十个示例标题,从而找到模式。

我仍然不明白他们为什么这样做而不是使用标准格式。与仅使用 ZLib 相比,获得一种新的压缩格式肯定是相当多的工作。如果他们试图混淆数据,他们可以通过对其进行加密、与其他值进行异或等来更有效地做到这一点。不,没有。我想,他们只是决定向他们的老板炫耀他们的天才,提出一些“新”的东西,即使与标准的差异微不足道,而且除了让我的生活变得困难之外没有任何价值。 :)

感谢提供意见的人。

【讨论】:

  • 感谢您带着结果回来 - 我会很感激负面的。为获得更多信息,请添加所投入时间的顺序。
  • 哈,我不会欣赏否定的结果。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-13
  • 2013-06-12
  • 1970-01-01
相关资源
最近更新 更多