Protobuf-net 无法识别的流前缀

Protobuf-net unrecognized stream prefix

我正在尝试对 Quasar RAT protobuf 协议结构进行逆向工程。 Quasar 是一个用 C# 编写的远程管理工具,它是开源的,可以在此处在线找到。 https://github.com/quasar/QuasarRAT

我已经设法逆转了大部分,现在我可以从 python 脚本连接到 Quasar 服务器客户端。有一个问题仍然悬而未决,似乎从客户端发送到服务器的每个字节流都以一个 3 字节字段开头,该字段未在 Quasar 的 protobuf class 中注册。该字段似乎提供了不包括前缀字节的消息长度。在此块中可以看到,例如为大小为 0x2d2 的数组生成的前缀字节流,这些是附加到消息的前缀字节。

0x0A, 0xCF, 0x05

如果我决定在序列化消息之前如何更改消息字段,则此字节流将发生变化,除了第一个 0x0A 字节。似乎如果我继续将字节附加到消息字段,第二个字节会增长,如果我溢出第二个字节(使其达到 0xff 以上) - 它会增加第三个字节并重置第二个字节为 0x80。但是数学对我来说根本没有意义,因为这个字段应该 return 数组的大小,但不符合我可以计算的任何合理公式。我知道 protobuf-net 可以生成 PreLengthPrefix 字节来为消息添加长度前缀,但这里不是这种情况。

如有任何帮助,我们将不胜感激。

编码规则在这里:https://developers.google.com/protocol-buffers/docs/encoding

基本上,每个字段都编码为 field-header(又名 "tag"),后跟一个有效负载。 field-header是一个"varint"(见编码指南),其值是由字段号和wire-type组成的整数。 wire-type 是 3 个最低有效位,字段号是其余的(移动 3 位)。以0x0A(二进制1010)为例,线型为2(二进制010),字段号为1.

如何处理有效载荷取决于电线类型。对于线类型 2(长度前缀),您应该期待下一个:

  • 一个 varint,它是有效负载的字节长度,然后
  • 实际负载的那么多字节

不幸的是,protobuf 在没有模式的情况下是模棱两可的,所以知道您有长度前缀数据并不能告诉您数据 是什么;长度前缀有效载荷可以是:

  • UTF-8 字符串
  • 原始 BLOB (bytes)
  • 一个sub-message
  • 一个"packed"一些基本类型的数组(integers/floating点numbers/etc)——记住长度前缀是字节的数量, 不是元素的数量;元素甚至不一定是固定大小(它们本身可以是 varints

在很多方面,电线类型的目的不是告诉您如何解释数据;而是告诉您如何解释数据。它是告诉您如何 跳过 (或者只是逐字存储)您不知道的字段。例如,其他人正在使用 API 的 V3,而您只将架构更新为 V2;他们向您的 V2 API 发送 V3 消息; V3 有您不关心的额外字段 - 反序列化器在遇到它们时需要不中断,因此线路类型告诉它如何忽略该字段(即规则的用途查找下一个字段)。否则,我们可以只使用模式信息而不将线路类型存储在有效载荷中 根本(尽管它也被用作对重复原始数据的优化,通过 "packed"数组 - 是否编码如 length-prefixed 与大量字段 header/value 对)取决于序列化器。