逆向工程部分已知的二进制格式

逆向工程 文件格式 工具 编码 二元诊断
2021-06-14 20:27:30

我有二进制数据的文件,它们的格式描述非常模糊和不完整。例如,它声明记录以头字节开始,如(十六进制)FA,然后是日期时间(精确到毫秒)和其他数据字段,但没有指示字段长度、最低有效位 (LSB) 值,甚至字节记录字段的字节序。总的来说,这些文件应该代表某种消息日志,我需要将它们正确解码为有意义的数据。

鉴于格式描述中的模糊、不完整和可能的错误(见下文),我实现目标的唯一希望是我拥有的表格。它大致描述了二进制文件中的内容。例如,我知道特定文件中的某些字段必须解码为接近 2700 的值,另一个字段必须为 -8.77 等。每个文件最多有一个这样的记录语句。

我首先阅读了这个问题,但我不确定哪些工具可以帮助我解决问题。所以我已经将我的输入二进制文件翻译成文本文件,简单地以十六进制表示形式显示初始数据,全部在一个大字符串中。按标头字节拆分它会产生一些奇怪的图片,其中每个记录似乎具有不同的字节长度。进一步的调查表明,标题的类型(我称它们为子标题)比格式描述中描述的要多。此外,第一个 1 字节字段似乎表示记录另外具有多少内部 22 字节数据块。第一个字段不合适 - 从格式描述来看,它应该是日期时间。所以,它不是那么准确/值得信赖,但至少它把我(似乎)推向了正确的方向。

我对逆向工程完全陌生,所以我的问题可能很糟糕,但请耐心等待:

  1. 鉴于所描述的情况,我的任务是否有可能完成?

  2. 如果是,我应该如何尝试找到一种解码方法?什么工具可以帮助找到正确的字段长度、LSB 和语义(即,哪个数据字段是哪个,因为我不再太相信该格式描述)?

编辑:有关调查结果的其他信息

下面是一些内部 22 字节块的示例。其中一条记录有 7 个块:

0018001E030825411C004303076D000D230000013802
0018002B020B56010C001C030011000D22065D011601
0018003103166A0052001803000A000D22065D011601
00187F7301197440390017030779000D22065D011701
0018002B02230540390019030779000D22065D011E01
00187F7E032578004A0024030009000D22065D012B01
00180038012B2501040028030010000D230000013101

以“FE070F600710”为前缀,其中“07”表示其中有 7 个,“0F600710”似乎在整个文件的此类前缀中重复出现。不同的 8 块记录示例:

00187F4C020614414E0030030767000D230000012001
00187F4E000669414E0031030767000D230000012301
00180014030E3B004A0028030009000D230000012601
0018002B0110694042001B030778000D230000011C01
00187F620321080052001203000A000D230000011601
0018000B00254440390028030779000D230000012E02
0018001601345C00420018030008000D230000012401
0018002B013923404A0010030777000D230000011E01

正如我们所见,它们都以“0018”开头,因此这可能是另一个子标题,而不是数据。这给我们留下了正好五个 4 字节浮点数,或两个 8 字节双精度数和额外的 4 个字节。

可以看到一些列“00”,“0D”似乎也在列模式中重复。还有一个“03”也一直存在。如果我们将它们视为额外的分隔符,7、1、2 和 6 字节的字段就可以猜到,这与某些标准的单精度或双精度浮点数不同。这就是为什么在最初的陈述中我认为实数被编码为整数,带有一些未知的 LSB。

3个回答

编辑:

出于历史目的,我将保留我以前的帖子/编辑,但鉴于此评论

另外,我想在您的帮助下尽可能多地尝试自己解决它,而不是您为我解决它。

我想我不会继续尝试在格式上取得进展。虽然根据我之前的观察,我确实有一些额外的想法。

所以直接回答原来的两部分问题:

  1. 鉴于所描述的情况,我的任务是否有可能完成?

这可能会也可能不会,这取决于最终目标是什么以及有哪些资源可用。

如果您有足够的数据样本,并且具有创建这些样本的输入的匹配知识,那么就有可能找出表示这些输入的格式部分,如果这就是您所需要的。拥有格式描述可能会有所帮助,即使它不精确或不准确。

但是,如果目标是完全理解数据格式(例如,编写一个 100% 兼容的实现),那么在我(新手)看来,如果不访问读取/写入文件(如果没有其他原因,您需要一种方法来验证假设)。如果您有大量的数据样本,所有领域的数据值都有足够的变化,这也许是可能的,但我认为这将是一场艰苦的斗争,而且理解率很可能达不到 100% .

  1. 如果是,我应该如何尝试找到一种解码方法?什么工具可以帮助找到正确的字段长度、LSB 和语义(即,哪个数据字段是哪个,因为我不再太相信该格式描述)?

在我看来,没有工具可以做到这一点,因为是逆向工程的人为部分。当然有十六进制编辑器,还有像 010 Editor 或 Kaitai Struct 这样的工具或二进制 diff 工具可以帮助你完成人类的部分,但实际上弄清楚一切代表什么以及它们如何组合在一起并不是(据我所知)可以通过工具完成的事情,特别是当您只有数据文件而不是机器代码时。(有一些工具可以对可执行代码进行自动分析,但我的印象是数据文件是另一类问题)。

祝你好运,我希望你能弄清楚。


以前的:

需要注意的是,我在 RE 方面仍然是新手,我根据发布的样本进行了一些观察。

如果您可以查看您拥有的其他数据样本并验证/反驳以下假设,那将会很有帮助。我会在您的回应和我取得进一步进展时进行更新。

到目前为止的观察和假设:

(字节偏移从 0 开始)

字节 02-03:16 位整数。值得注意的是小的正值和接近 INT16_MAX 的值并置,中间没有任何值。这让我想知道原始值是否可能为负,但符号位在转换过程中被剥离了。或者,没有任何转换问题,数据只是双模态的。

另外:如果您可以提供有关日志应该代表什么和/或生成日志的内容的更多详细信息,那将很有帮助。关于预期值的更多信息(例如,您说“接近 2700”和“必须是 -8.77”)以及它们代表什么。一般来说,上下文通常是有帮助的。更多的样本也可能有帮助。

字节 04:8 位整数。可能代表一个枚举。值似乎总是在 0x00-0x03 的范围内。

字节 05-06:字节 05 似乎在一组记录中单调增加。步长是可变的,所以可能不是计数器,但它可以指示某种时间戳或时间偏移。我目前的想法是 5-6 可能是“自 T 以来的毫秒数”,其中 T 是文件中其他地方的参考时间。如果组之前的标题应该包含时间戳,那么它可能与时间戳相关。

但是,该字段为 16 位的事实意味着至少每分钟(大约)需要一个新的参考时间戳,否则该字段会溢出。您拥有的数据样本是否反映了这种行为?

这就是我目前所拥有的。我稍后再回来查看。

我正在开发一些用于自动逆向工程的工具。

拥有不同长度的消息可以更容易地确定哪些字段与整体消息长度相关。它还可以更容易地识别“标题”部分的位置,因为它具有一致的格式并位于可变长度部分之前。

数据越多,数据越多样化,推断格式就越容易。很多次我看到通过保持所有内容不变并更改内存中的单个值来生成数据集。人类更容易发现校验和,但很难找到一般的字段边界。

这是我对给定数据格式的最佳猜测。看起来它是大端,字节 3 看起来像一个标签。| 表示存在启发式字段边界的地方。

    TTTTTTTT ?? FFFFFFFF | ???? | ?????? | ?????? TTTTTTTT | ??
    --
    00187F4C 02 0614414E | 0030 | 030767 | 000D23 00000120 | 01
    00187F4E 00 0669414E | 0031 | 030767 | 000D23 00000123 | 01
    00180014 03 0E3B004A | 0028 | 030009 | 000D23 00000126 | 01
    0018002B 01 10694042 | 001B | 030778 | 000D23 0000011C | 01
    00187F62 03 21080052 | 0012 | 03000A | 000D23 00000116 | 01
    0018000B 00 25444039 | 0028 | 030779 | 000D23 0000012E | 02
    00180016 01 345C0042 | 0018 | 030008 | 000D23 00000124 | 01
    0018002B 01 3923404A | 0010 | 030777 | 000D23 0000011E | 01
    --
    0 T  BE TIMESTAMP 32
    1 ? UNKNOWN TYPE 1 BYTE(S)
    2 F BE FLOAT 
    3 ? UNKNOWN TYPE 2 BYTE(S)
    4 ? UNKNOWN TYPE 3 BYTE(S)
    5 ? UNKNOWN TYPE 3 BYTE(S)
    6 T  BE TIMESTAMP 32
    7 ? UNKNOWN TYPE 1 BYTE(S)

我认为第 4 节中有某种序列(可能只是最后 2 个字节)。

22 字节:一个简单的猜测,如果每个块包含一个浮点值双精度
X.XXXXXXXXXXXXXXXe + XXX(len 22 字节)。
也许这有点太简单了,你能给我们一些你的 22 字节块的例子吗?

只是在阅读 Bill B 的有趣答案后发表评论:
没有值 > 0x7f
我猜这对于浮点数 8.77 来说是不可能的。