сырой декодер для формата protobufs - PullRequest
19 голосов
/ 08 сентября 2011

Я хотел бы найти способ преобразовать двоичное сообщение protobuf в удобочитаемое описание содержащихся в нем данных без использования файлов .proto.

На заднем плане у меня есть сообщение .protoчто он был отклонен парсером на Android, но не совсем понятно, почему.Я мог бы просмотреть сообщение вручную, но оно довольно утомительно.

Я попытался protoc --decode_raw, но оно просто выдает ошибку «Не удалось проанализировать ввод».Я гуглюсь, надеюсь / ожидаю, что кто-то сделал бы хорошую веб-утилиту, которая могла бы сделать это, но не нашел ничего очевидного.

Я просто надеюсь получить какой-то вывод, такой как:

field 1: varint: 128
field 4: string: "foo"

Любые указатели в правильном направлении будут приветствоваться!

Ответы [ 4 ]

28 голосов
/ 12 сентября 2012

Для потомков: буфер протокола Google У инструментов есть возможность декодировать необработанные буферы.

Просто отправьте в него неизвестный буфер и передайте флаг --decode_raw

$ cat has_no_proto.buff | protoc --decode_raw
2 {
  2: "Error retrieving information from server. [RH-02]"
}

Итак, вот сообщение с полем 2, установленным как встроенное сообщение, в котором второе поле имеет строку, сообщающую мне, что я разозлился из Google Play.

Информация о типе не определена (похоже,он попытается отобразить все двоичные данные в виде строк - но ваше требование для различия varint / string / submessage выполнено).

8 голосов
/ 21 февраля 2016

Как отмечается в ответ Мишеля де Рюйтера , вполне возможно, что ваше сообщение protobuf имеет префикс length . Предполагая, что это так, этот ответ должен помочь.

(ПРИМЕЧАНИЕ. Для большинства приведенных ниже команд я предполагаю, что ваше сообщение protobuf хранится в файле с именем input.)

protoc --decode_raw + dd для одного сообщения:

Если это просто одно сообщение, тогда вы действительно можете использовать protoc --decode_raw, но сначала вам нужно удалить заголовок префикса длины. Предполагая, что заголовок имеет длину 4 байта, вы можете использовать dd, чтобы удалить заголовок из input, а затем передать вывод в protoc.

dd bs=1 skip=4 if=input 2>/dev/null | protoc --decode_raw

protoc-decode-lenprefix --decode_raw для одного сообщения:

Я также написал скрипт , который автоматически обрабатывает удаление заголовка:

protoc-decode-lenprefix --decode_raw < input

Этот скрипт - просто оболочка над protoc --decode_raw, но он обрабатывает разбор заголовка префикса длины и затем вызывает protoc.

Теперь этот сценарий не очень полезен в этом случае, потому что мы можем просто использовать вышеприведенный трюк dd, чтобы удалить заголовок. Однако, скажем, у нас есть поток данных (например, файл или поток TCP), содержащий несколько сообщений, которые обрамлены заголовками с префиксом длины ....

protoc-decode-lenprefix --decode_raw для потока сообщений:

Вместо одного сообщения protobuf во входном файле, скажем, input содержало несколько сообщений protobuf, которые обрамлены заголовками с префиксом длины. В этом случае невозможно просто использовать трюк dd, потому что вам нужно фактически прочитать содержимое заголовка префикса длины, чтобы определить, как долго последующее сообщение в потоке, и, следовательно, как много байтов впереди следующий заголовок + сообщение лежит. Таким образом, вместо того, чтобы беспокоиться обо всем этом, вы можете просто использовать protoc-decode-lenprefix снова:

protoc-decode-lenprefix --decode_raw < input

protoc-decode-lenprefix --decode ... foo.proto для потока сообщений

Этот сценарий также можно использовать для полного декодирования сообщений с префиксом длины (вместо простого «сырого декодирования» их). Предполагается, что у вас есть доступ к .proto файлам, которые определяют сообщение protobuf, так же как и обернутая команда protoc. Синтаксис вызова идентичен protoc --decode. Например, используя трюк dd с protoc --decode вместе с входным файлом Mesos task.info , синтаксис выглядит следующим образом:

dd bs=1 skip=4 if=task.info 2>/dev/null | \
protoc --decode mesos.internal.Task \
                      -I MESOS_CODE/src -I MESOS_CODE/include \
                      MESOS_CODE/src/messages/messages.proto

И параметры идентичны при использовании protoc-decode-lenprefix

cat task.info | \
protoc-decode-lenprefix --decode mesos.internal.Task \
                      -I MESOS_CODE/src -I MESOS_CODE/include \
                      MESOS_CODE/src/messages/messages.proto
8 голосов
/ 06 января 2016

Если у вас есть двоичный файл, содержащий (несколько?) префикс длины сообщений protobuf, protoc ‒‒decode_raw < file не сможет проанализировать его из-за префиксов длины.Простой способ обойти это - разделить файл на последовательные сообщения и , а затем преобразовать каждое с protoc.

Мой дубль:

var fs = File.OpenRead(filename));
var buffer = new byte[4096];
int size;
for (int part = 1; Serializer.TryReadLengthPrefix(fs, PrefixStyle.Base128, out size); part++) {
  long startPosition = fs.Position;
  using (var writer = File.OpenWrite(string.Format("{0}[{1}].pb", filename, part))) {
    for (int bytesToRead = size; bytesToRead > 0; ) {
      int bytesRead = fs.Read(buffer, 0, Math.Min(bytesToRead, buffer.Length));
      bytesToRead -= bytesRead;
      if (bytesRead <= 0) // End of file.
        break;
      writer.Write(buffer, 0, bytesRead);
    }
  }
}
6 голосов
/ 08 сентября 2011

Вы можете попытаться форсировать его через плагин wireshark, или вы можете позаимствовать часть «читателя» некоторых реализаций (например, я знаю, как бы я это делал в C #, но я сомневаюсь, что вы это имели в виду).

Однако будьте осторожны - строка в буферах протокола на самом деле не означает «строка» - это может быть:

  • строка UTF-8
  • необработанный большой двоичный объект произвольных данных
  • под-сообщение
  • "упакованный" массив
  • (вероятно, что-то еще, что я забыл)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...