
Ein Werkzeugsatz für Reverse Engineering und Fuzzing von Protobuf-basierten Anwendungen
Protobuf ist ein Serialisierungsformat, das von Google entwickelt wurde und in einer steigenden Anzahl von Android-, Web-, Desktop- und weiteren Anwendungen verwendet wird. Es besteht aus einer Sprache zur Deklaration von Datenstrukturen, die dann je nach Zielimplementierung in Code oder eine andere Art von Struktur kompiliert wird.
pbtk (Protobuf Toolkit) ist eine vollständige Sammlung von Skripten, die über eine einheitliche GUI zugänglich ist und zwei Hauptfunktionen bietet:
Extrahieren von Protobuf-Strukturen aus Programmen, die zurück in lesbare .protos konvertiert werden, mit Unterstützung für verschiedene Implementierungen:
Bearbeiten, Wiederholen und Fuzzing von Daten, die an Protobuf-Netzwerkendpunkte gesendet werden, über eine praktische grafische Oberfläche, die es Ihnen ermöglicht, die Felder einer Protobuf-Nachricht live zu bearbeiten und das Ergebnis zu sehen.
PBTK erfordert Python ≥ 3.5, PySide 6, Python-Protobuf 3 und einige ausführbare Programme (chromium, jad, dex2jar...), um die Extraktionsskripte auszuführen.
Ubuntu-Nutzer können es mit snap installieren:
$ sudo snap install pbtk
$ pbtk
Archlinux-Benutzer können es direkt über das Paket installieren:
$ yay -S pbtk-git
$ pbtk
Auf den meisten anderen Distributionen möchten Sie es wahrscheinlich direkt ausführen:
# For Ubuntu/Debian testing derivates:
$ sudo apt install python3-pip git openjdk-8-jre python3-qtpy-pyside6
# Then, using UV:
$ sudo snap install --classic astral-uv
$ uv tool install pbtk
$ pbtk
# Or using pipx:
$ sudo apt install pipx
$ pipx install pbtk
$ pbtk
Windows wird ebenfalls unterstützt (mit denselben erforderlichen Modulen). Sobald Sie die GUI ausführen, sollte sie Sie warnen, was Ihnen fehlt, je nachdem, was Sie versuchen.
Die GUI kann über das Hauptskript gestartet werden:
pbtk
Die folgenden Skripte können auch eigenständig ohne GUI verwendet werden:
pbtk-jar-extract [-h] input_file [output_dir]
pbtk-from-binary [-h] input_file [output_dir]
pbtk-web-extract [-h] input_url [output_dir] # Needs update to work as of 2026
Bei Installation über snap unterscheiden sich die genauen Befehle:
pbtk.jar-extract [-h] input_file [output_dir]
pbtk.from-binary [-h] input_file [output_dir]
pbtk.web-extract [-h] input_url [output_dir]
Die GUI kann über das Hauptskript gestartet werden:
uv sync # Download dependencies to the .venv folder
source .venv/bin/activate # Put the local scripts in $PATH for the current shell session
uv tool install -e . # Put the local scripts in $PATH all time
pbtk
Die folgenden Skripte können auch eigenständig ohne GUI verwendet werden:
pbtk-jar-extract [-h] input_file [output_dir]
pbtk-from-binary [-h] input_file [output_dir]
pbtk-web-extract [-h] input_url [output_dir] # Needs update to work as of 2026
Angenommen, Sie reverse-engineeren eine Android-Anwendung. Sie haben die Anwendung ein wenig mit Ihrem bevorzugten Decompiler erkundet und festgestellt, dass sie Protobuf als POST-Daten über HTTPS auf typische Weise transportiert.
Sie öffnen PBTK und werden auf sinnvolle Weise begrüßt:

Der erste Schritt ist, Ihre .proto-Dateien in Textformat zu bringen. Wenn Sie eine Android-App analysieren, sollte das Einwerfen einer APK und das Warten die Magie wirken lassen! (es sei denn, es handelt sich um eine wirklich exotische Implementierung)

Danach wechseln Sie zu ~/.pbtk/protos/<your APK name> (entweder über die Befehlszeile oder über die Schaltfläche unten auf dem Willkommensbildschirm, um Ihren Dateibrowser zu öffnen – ganz wie Sie möchten). Alle .proto-Dateien der App sind hier.
Zurück in Ihrem Decompiler stoßen Sie auf die Klasse, die die an den HTTPS-Endpunkt gesendeten Daten erstellt. Sie serialisiert die Protobuf-Nachricht, indem sie eine Klasse aus generiertem Code aufruft.

Diese letztere Klasse sollte eine exakte Übereinstimmung in Ihrem .proto-Verzeichnis haben (d.h. com.foo.bar.a.b wird mit com/foo/bar/a/b.proto übereinstimmen). So oder so sollte das Greppen des Namens es Ihnen ermöglichen, darauf zu verweisen.
Das ist großartig: Als nächstes gehen Sie zu Schritt 2, wählen Sie Ihr gewünschtes Eingabe-.proto aus und füllen einige Informationen über Ihren Endpunkt aus.

Sie können auch einige rohe Protobuf-Beispieldaten angeben, die an diesen Endpunkt gesendet wurden, erfasst über mitmproxy oder Wireshark, und die Sie hex-codiert einfügen.
Schritt 3 besteht aus dem spaßigen Teil: Klicken Sie auf Schaltflächen und sehen Sie, was passiert! Sie haben eine Baumansicht, die jedes Feld in der Protobuf-Struktur darstellt (wiederholte Felder sind mit „+“ versehen, erforderliche Felder haben keine Kontrollkästchen).

Fahren Sie einfach mit der Maus über ein Feld, um den Fokus zu erhalten. Wenn das Feld ein Integer-Typ ist, verwenden Sie das Mausrad, um es zu erhöhen/verringern. Enum-Informationen erscheinen ebenfalls beim Überfahren.
Hier ist es! Sie können damit die Bedeutung jedes Feldes bestimmen. Wenn Sie .proto-Dateien aus minimiertem Code extrahiert haben, können Sie Felder umbenennen, indem Sie auf ihre Namen klicken, entsprechend dem, was Sie für ihre Bedeutung halten.
Viel Spaß beim Reverse Engineering! 👌 🎉
PBTK speichert extrahierte .proto-Informationen in ~/.pbtk/protos/ (oder %APPDATA%\pbtk\protos unter Windows).
Sie können Daten aus diesem Verzeichnis direkt über Ihren normalen Dateibrowser und Texteditor verschieben, hinzufügen, umbenennen, bearbeiten oder löschen. Dies ist die erwartete Vorgehensweise und wird PBTK nicht stören.
HTTP-basierte Endpunkte werden als JSON-Objekte in ~/.pbtk/endpoints/ gespeichert. Diese Objekte sind Arrays von Paaren von Anforderungs-/Antwortinformationen, die wie folgt aussehen:
[{
"request": {
"transport": "pburl",
"proto": "www.google.com/VectorTown.proto",
"url": "https://www.google.com/VectorTown",
"pb_param": "pb",
"samples": [{
"pb": "!....",
"hl": "fr"
}]
},
"response": {
"format": "other"
}
}]
PBTK verwendet intern zwei Arten von steckbaren Modulen: Extraktoren und Transportschichten.
Extraktoren werden in src/pbtk/extractors/*.py definiert. Sie werden als Methode definiert, der ein Decorator vorausgeht, wie folgt:
@register_extractor(name = 'my_extractor',
desc = 'Extract Protobuf structures from Foobar code (*.foo, *.bar)',
depends={'binaries': ['foobar-decompiler']})
def my_extractor(path):
# Load contents of the `path` input file and do your stuff...
# Then, yield extracted .protos using a generator:
for i in do_your_extraction_work():
yield proto_name + '.proto', proto_contents
# Other kinds of information can be yield, such as endpoint information or progress to display.
Transportschichten werden in src/pbtk/utils/transports.py definiert. Sie werden als Klasse definiert, der ein Decorator vorausgeht, wie folgt:
@register_transport(
name = 'my_transport',
desc = 'Protobuf as raw POST data',
ui_data_form = 'hex strings'
)
class MyTransport():
def __init__(self, pb_param, url):
self.url = url
def serialize_sample(self, sample):
# We got a sample of input data from the user.
# Verify that it is valid in the form described through "ui_data_form" parameter, fail with an exception or return False otherwise.
# Optionally modify this data prior to returning it.
bytes.fromhex(sample)
return sample
def load_sample(self, sample, pb_msg):
# Parse input data into the provided Protobuf object.
pb_msg.ParseFromString(bytes.fromhex(sample))
def perform_request(self, pb_data, tab_data):
# Perform a request using the provided URL and Protobuf object, and optionally other transport-specific side data.
return post(url, pb_data.SerializeToString(), headers=USER_AGENT)
Folgendes könnte für zukünftige Versionen kommen:
Ich habe mein Bestes gegeben, um für die meisten Module einen gründlich lesbaren und kommentierten Code zu erstellen (außer für Teile, die weitgehend selbsterklärend sind, wie das Verbinden von GUI-Signalen), damit Sie beitragen können.
pbtk wird unter der GNU GPL-Lizenz veröffentlicht (ich, hiermit usw.).
Es gibt keine formalisierte Regel für die Groß-/Kleinschreibung des Projektnamens, die Regel ist einfach: Folge deinem Herzen ❤