我正在尝试调查一个二进制数据。我的猜测是它应该是类似文件系统的简单索引的一部分。文件分为两部分。第一部分的格式非常简单:


第一部分的字节数
许多零结尾的字符串,看起来像文件名(其中1256个)

自然,我希望以后能找到指向越来越多的指向使用这些字符串命名的文件的指针。但是,文件的其余部分为0x5c47字节长,看起来它具有许多记录(int32,little endian = 0x4e0),然后是一系列记录。但是,诀窍是显然记录长度不是恒定的:(0x5c47-4)/ 0x4e0〜18.9254807。我在这里看到某种模式,让我演示一下:

E0 04 00 00


正如我所说,它以记录数开始,0x4e0 =1248。请注意,1248条记录非常接近到我之前发现的字符串数(1256),但不完全匹配。然后我看到一些14字节长的记录:

90 00   |90 0D|90 16 02 90 22 90 2A 90 39|00
90 46   |90 0D|90 16 02 90 22 90 2A 90 39|01
90 53   |90 0D|90 16 02 90 22 90 2A 90 39|02
90 61   |90 0D|90 16 02 90 22 90 2A 90 39|03
90 6E   |90 0D|90 16 02 90 22 90 2A 90 39|04


最后一个字节似乎是记录号计数器。至于其他,到目前为止,仅第2个字节发生了变化。但是,接下来我们看到一些15字节长的记录: 90 00,然后最终溢出并变为90 4691 82 00,... 91 97 00等。但是,对于我过去使用的可变长度整数,它不是正常的编码(BER,AKA VLQ,AKA Base128等)。让我们检查一下一旦变成16字节长的记录,记录的内容将如何扩展:

91 82 00|90 0D|90 16 02 90 22 90 2A 90 39|05
91 97 00|90 0D|90 16 02 90 22 90 2A 90 39|06
91 A4 00|90 0D|90 16 02 90 22 90 2A 90 39|07
...
91 14 01|90 0D|90 16 02 90 22 90 2A 90 39|0E
,<43 79 91 26 0105(大概编码记录#0..15),然后跳转到06来指定记录#16。第一个字段似乎仍是3字节整数。下一步切换到17字节长的脚架,如下所示:

91 26 01|90 0D|90 16 02 90 22 90 2A 90 39|0F
91 39 01|90 0D|90 16 02 90 22 90 2A 90 39|80 10
91 4E 01|90 0D|90 16 02 90 22 90 2A 90 39|80 11
91 6C 01|90 0D|90 16 02 90 22 90 2A 90 39|80 12
91 8B 01|90 0D|90 16 02 90 22 90 2A 90 39|80 13
...


与我们之前看到的把07变成0E的技巧有些模糊的相似:在这里0F变成80 10大概是指从#126 = 0x7e(编码为90)切换到#127 = 0x7f(编码为91)。 />
文件中似乎还有一个用于18字节长记录的主要格式切换,我想它的排列方式如下:

...
91 7C 08|90 0D|90 16 02 90 22 90 2A 90 39|80 7D
91 8A 08|90 0D|90 16 02 90 22 90 2A 90 39|80 7E
91 98 08|90 0D|90 16 02 90 22 90 2A 90 39|81 7F 00
91 A6 08|90 0D|90 16 02 90 22 90 2A 90 39|81 80 00
91 B4 08|90 0D|90 16 02 90 22 90 2A 90 39|81 81 00
91 C2 08|90 0D|90 16 02 90 22 90 2A 90 39|81 82 00
...


此更改扩展了许多字段(实际上使它清楚了什么是字段边界),并将最后一个字段重置为0。将80变成81:这里80 7E变成81 7F 00,以指定从#126 = 0x7e(编码为90)切换到#127 = 0x7f(编码为91)。文件末尾的记录长20个字节,看起来像这样:

...
91 5D 14|90 0D   |90 16   |02|90 22|90 2A   |90 39|81 5C 01
91 6A 14|90 0D   |90 16   |02|90 22|90 2A   |90 39|81 5D 01
91 77 14|91 86 14|91 8F 14|02|90 22|91 9B 14|90 39|00
91 AA 14|91 86 14|91 8F 14|02|90 22|91 9B 14|90 39|01
91 B5 14|91 86 14|91 8F 14|02|90 22|91 9B 14|90 39|02
91 C0 14|91 86 14|91 8F 14|02|90 22|91 9B 14|90 39|03
91 CB 14|91 86 14|91 8F 14|02|90 22|91 9B 14|90 39|04
...


我最好的选择是,许多中间值都增加了,并且80变成了81。 br />
总结一下到目前为止我所学到的内容,看来这些记录使用的是可变长度编码的整数,编码方案如下:


0x0 = 80 7E = 81 7F 00

0x1 = 90 xx = 91 xx yy

...
0xf = 00 = 0000_0000

0x10 = 01 = 0000_0001

0x11 = 0F = 0000_1111

...
0x7e = 80 10 = 1000_0000|0001_0000

0x7f = 80 11 = 1000_0000|0001_0001

0x80 = 80 7E = 1000_0000|0111_1110

...
0x15d = 81 7F 00 = 1000_0001|0111_1111|0000_0000


是否有人知道任何标准格式/编码方案,看起来像那样吗?有关如何正确解码81 80 001000_0001|1000_0000|0000_0000值的任何想法?

评论

ASN1看起来像这样。 9x值可能是带有特殊类型的8x值(例如有符号对无符号)。

@peterferrie ASN1的可变长度整数的概念基本上是Base128 +一些像标签和类型的钟声。 Base128表示值<128的只有一个字节。这里肯定有更多:我们早在0x10时就使用每个整数2个字节。感谢您对有符号与无符号的见解:)

#1 楼

记录中的八个字段中的每个字段都有一个字节的标头。当然);低nybble是对数字进行编码所需的字节数(不计算头字节),减一。 :非常小的与8相同类型的数字,在这种情况下,低半字节就是整数。数字的其余部分使用一种自行发送编码长度信号的方法进行编码,浪费了很多时间,没有意识到标头已经告诉我们编码需要多少字节。我的猜测是,在确定了内部编码之后,此应用程序才“发明了”头字节。

对于正整数,内部编码与VLQ非常相似(感谢删除名称,我不知道这些):将数字的最低7位作为一个字节输出,如果要跟随的字节数更多,则将该字节的MSB设置为1;否则将其设置为0;否则,将其设置为0。继续下一个7位,等等。
与VLQ的不同之处在于,将位序列9视为非终止,这可能是编码器中的Obi-Wan错误,或者是某种真正的设计决策我不太了解。 (不能用信号表示该数字不应以负号扩展为负,因为这对于0-8同样适用。)从头开始-它应该以值0x1fe结尾,并且我希望它将被编码为8(请注意,0x1ff被编码为9,这意味着该编码在任何地方都不会使用值7F。)

您的样本中没有负数的示例,因此我们无法确定它们将如何编码。