Package: protobuf-inspector
protobuf-inspectorSimple program that can parseGoogle Protobufencoded blobs
(version 2 or 3) without knowing their accompanying definition.
It will print a nice, colored representation of their contents. Example:As you can see, the field names are obviously lost, together with
some high-level details such as:whether a varint useszig-zag encodingor not (will assume no zig-zag by default)whether a 32-bit/64-bit value is an integer or float (both shown by default)signedness (auto-detect by default)But protobuf-inspector is able to correctly guess the message structure
most of the time. When it finds embedded binary data on a field, it'll
first try to parse it as a message. If that fails, it'll display the data
as a string or hexdump. It can make mistakes, especially with small chunks.It shows the fields just in the order they are encoded in the
wire, so it can be useful for those wanting to get familiar with
thewire formator parser developers, in addition to reverse-engineering.UsageYou can install with pip:pip install protobuf-inspectorThis installs theprotobuf_inspectorcommand. Run it, feeding the protobuf blob
on stdin:protobuf_inspector < my-protobuf-blobAfter reading the first (blind) analysis of the blob, you typically start defining
some of the fields so protobuf-inspector can better parse your blobs, until you get
to a point where you have a full protobuf definition and the parser no longer has
to guess anything.Read about defining fields here.Parsing errorsIf a parsing error is found, parsing will stopwithin that field, but
will go on unaffected at the outside of the hierarchy. The stack trace will
be printed where the field contents would go, along with a hexdump indicating where
parsing was stopped in that chunk, if applicable.So, if you specified auint32and a larger varint is found, you'd get something like:If you specified that some field contained an embedded message, but invalid data was
found there, you'd get:Please note thatmain.pywill exit with non-zero status if one or more parsing
errors occurred.TricksThere are some tricks you can use to save time when approaching a blob:If you are positive that a varint doesnotuse zig-zag encoding, but are still
not sure of the signedness, leave it asvarint. If it does use zig-zag encoding,
usesint64unless you are sure it's 32-bit and not 64-bit.If a chunk is wrongly being recognized as apacked chunkor an embedded message,
or if you see something weird with the parsed message and want to see the raw bytes,
specify a type ofbytes. Conversely, if for some reason it's not being detected
as an embedded message and it should, force it tomessageto see the reason.If you want to extract a chunk's raw data to a file to analyze it better, specify a
type ofdumpand protobuf-inspector will createdump.0,dump.1,
etc. every time it finds a matching blob.protobuf-inspector parses the blob as a message of typeroot, but that's just a
default. If you have lots of message types defined, you can pass a type name as
optional argument, and protobuf-inspector will use that instead ofroot:protobuf_inspector request < my-protobuf-blobProgrammatic accessSimple example:fromprotobuf_inspector.typesimportStandardParserparser=StandardParser()withopen('my-blob','rb')asfh:output=parser.parse_message(fh,"message")print(output)This project was not initially designed for use as a library, though,
and its API might change. For a more complex example,
seeprotobuf_inspector/__main__.py.