解码古老的格式

逆向工程 二元分析 文件格式
2021-07-03 07:07:46

这是一种非常有趣的文件格式,可能会极大地满足二进制考古学家的需求。示例文件

背景

这种文件格式是在 90 年代创建的,用于归档客户创建的 AutoCAD 组件库,如窗、门和柱。第一行是纯文本xxxx DWG library 1.0,已从示例文件中删除以避免出现任何问题。xxx 公司已经消失了,但不确定是否还有人持有该商标。我父亲的很多设计文件都依赖于它。

这种文件格式有一个配套的索引/参考文件,它是一个简单的 dBase III。工作平台为DOS/Windows。

发现

我花了2天时间试图理解格式。虽然离全貌还很远,但我所得到的是:

  • 它由两部分组成,一个文件列表部分和一个 blob 数组部分
  • 文件列表部分是一个简单的文件名数组 +一个神话般的 3 字节文件代码(我们称之为 m1) m1 指向其二进制2 字节的位置左边的 1 个字节似乎与文件/记录名称有关。一个 4 字节的 int 指向其对应二进制文件的位置。
    • 文件名的长度为 0x20,空格用 0x00 填充。
    • m1 不是通常的位置偏移。
    • 文件记录以 0x00 分隔
  • blob 数组部分很有趣。
    • 每个 blob 都以“AS LZW 1.0”开头(不要错过尾部空间)
    • 然后是 2 个字节的未知用法。不是随机的。示例:0x6323、0x5b23、0xfa22、0x0223。(称之为 m2)解码二进制文件的大小。
    • 6 个字节的 0x00
    • 2 字节的未知用法。不是随机的。主要是 0x9ccc(称之为 m3)
    • 然后 0xaa08 + 12 个字节的 0x00
    • LZW 旧式编码二进制:0c00 0000 0083 0c89 0123 460d 0008 113e 08c0 ...

问题

  1. blob 数组部分中的 blob 真的是用 LZW 压缩的吗?我试图从 m2、m3 位置用 python lzw 解码,但都失败了。
  2. m1 是解码 blob 的关键吗?
  3. 什么是的使用M2, M3?
  4. 有没有通用的方法来解码这样的文件格式?(好吧,我只有 google :( 和文件签名列表010 编辑器(不错的软件,谢谢@0xC0000022L)

更新

  • m1 是 3 个字节。因此排除了 blob 条目是 CRC16 的可能性。
  • 感谢@0xC0000022L 的评论。文件的第一行是:ArchStar DWG Library 1.0(以0x0d结尾)
  • 在 blob 上尝试了Trid(在砍掉“AS LWS 1.0”之后),它报告

    100.0% (.CEL) Autodesk FLIC 图像文件(扩展名:flc、fli、cel)(7/3)

    没有意义。

21/11/13 更新

进步LZW蟒蛇似乎是最近的事。所以我研究了上个世纪旧的 LZW 实现。所以我找到了libtiff的 lzw 模块,它是python 实现(必须在其中使用 bitarray 模块:版本 0.35 而不是最新版本)。我用蛮力方法尝试了这个python库(感谢@Attila),blob确实可以从28小时开始解码(基于:“AS LZW”)。最重要的是,解码以“AC10”开头,AutoCAD DWG 格式!然而,它只解码了大约 30% 的 blob。

进度 2从 golang尝试lzw,解码配置顺序为:LSB 和 litWid:2,解码了大约 3 倍的数据。明天将报告更多结果。

进度3使用python LibTiff LZW 解码的dwg 是有效的AutoCAD DWG。AutoCAD 2014 报告从 golang LZW 解码的一个无效。现在我猜 blob 的其余部分是矢量的图像缩略图。将解码所有 50 个 blob 并返回报告。

22/11/13 更新

使用 libtiff lzw (lzw.py) 解码的 blob 无效,尽管它们具有正确的标头“AC10”。

我仔细查看了pylibtiff里面的lzw.py,发现了前两行:

""" TIFF 的 Lempel-Ziv-Welch 算法的编码器和解码器。

此模块已过时,请改用 tif_lzw 扩展模块。"""(经验教训:阅读每一行!)

所以我修改了我的代码以使用 tif_lzw 来解码 blob。没有运气。这一次,我仔细阅读了代码,一行一行。

乍一看,该文件还有两个 Python 包装方法 Py_decode 和 Py_encode。然后我注意到旧式 LZW 代码的禁用方法 LZWDecodeCompat 这有点有趣。所以我修改了模块,启用了 LZWDecodeCompat 并在 Py_decode 方法中使用它。tif_lzw.decode 方法需要一个额外的参数size当然,我使用了 m1(对于第一个 blob,我使用了 0x4c07)。解码结果有“AC10”标题,在AutoCAD(mac ver)中成功打开但什么也没显示。AutoCAD 说它是受信任的 DWG,包含 1 个我找不到的块。所以我花了好几个小时安装了 Windows 和 AutoCAD。答对了!有柱图!还有一些问题。例如,仍然无法为 tif_lzw.decode 方法调用找到合适的大小。

progress解码了所有 50 个二进制文件:

  • tif_lzw LZWDecodeCompat
  • 使用 m3 作为大小参数

模板(进行中)

struct FILE {

    char banner[26];
    char f1[2];
    FSkip(4); //char sp[4];

    local int count = 0;
    local int pos;
    local char sp[36];
    local char SP[36];
    Memset(SP, 0, 36);

    while(true){
        pos = FTell();
        ReadBytes(sp, pos, 36);

        if(Memcmp(sp, SP, 36) == 0){
            break;
        }
        count ++;
        FSeek(pos);

        struct {
            char name[32];
            DWORD loc;
        } index;
    }


    FSkip(36); //char sp2[36];
    struct Binary(int len){
            char banner[11];
            WORD size;
            FSkip(7);//char sp[7];
            char m3[2]; // CRC16?
            char m4[2]; // always AA 08
            FSkip(16);
            char lzw[len];
    };

    local int i;

    for(i = 1; i < count; i++){
        Binary b(index[i].loc - index[i-1].loc - 40);
    }

    if(count>0){
        Binary b(FileSize() - index[i-1].loc - 40);
    }
} file;
2个回答

考虑更改您的 Python 脚本以从各种偏移量运行 LZW 解压缩,这是一种蛮力方式。

随意编辑这个社区维基“答案”。

注意:只写这个作为答案,因为评论太长了。我认为鉴于这些零碎的信息,除非您很幸运并且有人碰巧知道这种特定的文件格式,否则没有答案。

如果我们假设文件格式确实与 DWG 有关,我们可以通过查看 DWG 的规范或新规范(Google 搜索OpenDesign_Specification_for_.dwg_files.pdf)并找出它们使用的文件格式来了解很多。特别感兴趣的是数据类型(参见链接论文的“位代码和数据定义”和“压缩”)和算法。例如,在上述部分中,我们发现:

AutoCAD DWG 文件格式使用标准循环冗余校验的修改作为错误检测机制。由于在包含 256 个 16 位值的表中查找,CRC 最终为 2 个字节长,并且不以任何类型的位代码形式存储。它们也总是出现在字节边界上;它们没有嵌入到比特流中。

这是非常有价值的信息,可以帮助您确认调查结果。

同样有趣的是,假设这适用于您的情况:

Autodesk 还使用一种方法,将 CRC 的结果与“幻数”进行异或。此方法广泛用于 R13 之前的文件 [...]

BricsCAD 和其他公司提供 SDK 和库(和产品),他们声称它们也能理解旧的 DWG 格式。

但是回到自己调查格式。

您将需要使用诸如 010 Editor 之类的工具,该工具允许您创建模板并以这种方式从字面上发展您对文件格式的理解。

现在,您通过声明第一行是文本但没有给出长度或无论如何都没有给出您如何得出它是纯文本的结论,从而剥夺了我们的重要信息。

例如AS LZW 1.0,文件中有 50 次出现尽管如此,我还是在开始时计算了更多出现的神秘 ASCII 数字。可能这也会计算一些不需要AS LZW 1.0位的标记

那些小数也是从 2 开始的。为什么?

老实说,我也无法按照您的描述进行操作。如果第一部分是文件名并用 分隔00,那为什么00那部分出现了这么多的

ArchStar 解释了AS LZW 1.0当然。那么它可能是“正常”LZW的变体。LZW当然也可以代表一些不相关的东西,比如作者的姓名首字母或他们的名字。


关于 CEL/FLIC 文件的更新。如果我们假设这里的信息是正确的,我们应该在这里看到一些有用的东西。但它确实看起来像胡言乱语。

在此处输入图片说明

所以我同意,可能没有 FLIC 文件。不过,请记住,DWG 来自同一个创建者。这可能不是巧合。


关于 LZW 数据调查结果的更新。来自维基百科(这里):

通过这种方式,解码器构建了一个与编码器使用的字典相同的字典,并使用它来解码后续的输入值。因此不需要与编码数据一起发送完整字典;仅包含单字符串的初始字典就足够了(并且通常在编码器和解码器中预先定义,而不是与编码数据一起显式发送。)

(加了重点。)