
🕵️ Outil de rétro-ingénierie des Protocol Buffers avec une définition inconnue
Programme simple capable d'analyser des blobs encodés avec Google Protobuf (version 2 ou 3) sans connaître leur définition associée. Il affiche une représentation colorée et agréable de leur contenu. Exemple :

Comme vous pouvez le constater, les noms des champs sont évidemment perdus, tout comme certains détails de haut niveau tels que :
Mais protobuf-inspector est capable de deviner correctement la structure du message la plupart du temps. Lorsqu'il trouve des données binaires intégrées dans un champ, il essaie d'abord de les analyser comme un message. Si cela échoue, il affiche les données sous forme de chaîne ou de hexdump. Il peut faire des erreurs, surtout avec des petits blocs.
Il affiche les champs dans l'ordre même où ils sont encodés sur le fil, ce qui peut être utile pour ceux qui souhaitent se familiariser avec le format wire ou les développeurs d'analyseurs, en plus du rétro-ingénierie.
Vous pouvez l'installer avec pip :
pip install protobuf-inspector
Cette commande installe la commande protobuf_inspector. Exécutez-la en fournissant le blob protobuf
sur l'entrée standard :
protobuf_inspector < my-protobuf-blob
Après avoir lu la première analyse (aveugle) du blob, vous commencez généralement à définir certains des champs afin que protobuf-inspector puisse mieux analyser vos blobs, jusqu'à atteindre un point où vous avez une définition protobuf complète et l'analyseur n'a plus rien à deviner.
Lisez à propos de la définition des champs ici.
Si une erreur d'analyse est détectée, l'analyse s'arrête à l'intérieur de ce champ, mais se poursuit sans être affectée en dehors de la hiérarchie. La trace de la pile sera affichée à l'endroit où le contenu du champ irait, ainsi qu'un hexdump indiquant où l'analyse s'est arrêtée dans ce bloc, le cas échéant.
Donc, si vous avez spécifié un uint32 et qu'un varint plus grand est trouvé, vous obtiendrez quelque chose comme :

Si vous avez spécifié qu'un champ contenait un message incorporé, mais que des données invalides y ont été trouvées, vous obtiendrez :

Veuillez noter que main.py se terminera avec un statut non nul si une ou plusieurs erreurs d'analyse
se sont produites.
Il existe quelques astuces que vous pouvez utiliser pour gagner du temps lorsque vous abordez un blob :
Si vous êtes certain qu'un varint n'utilise pas l'encodage zig-zag, mais que vous n'êtes toujours
pas sûr du signe, laissez-le en tant que varint. S'il utilise l'encodage zig-zag,
utilisez sint64 sauf si vous êtes sûr qu'il est 32 bits et non 64 bits.
Si un bloc est reconnu à tort comme un packed chunk ou un message incorporé,
ou si vous voyez quelque chose d'étrange avec le message analysé et souhaitez voir les octets bruts,
spécifiez un type bytes. Inversement, si pour une raison quelconque il n'est pas détecté
comme un message incorporé alors qu'il devrait l'être, forcez-le à message pour en voir la raison.
Si vous souhaitez extraire les données brutes d'un bloc dans un fichier pour mieux l'analyser, spécifiez un
type dump et protobuf-inspector créera dump.0, dump.1,
etc. chaque fois qu'il trouvera un blob correspondant.
protobuf-inspector analyse le blob comme un message de type root, mais ce n'est qu'un
défaut. Si vous avez beaucoup de types de messages définis, vous pouvez passer un nom de type comme
argument optionnel, et protobuf-inspector utilisera celui-ci au lieu de root :
Exemple simple :
from protobuf_inspector.types import StandardParser
parser = StandardParser()
with open('my-blob', 'rb') as fh:
output = parser.parse_message(fh, "message")
print(output)
Ce projet n'a pas été conçu initialement pour être utilisé comme bibliothèque,
et son API pourrait changer. Pour un exemple plus complexe,
consultez protobuf_inspector/__main__.py.
protobuf_inspector request < my-protobuf-blob