
Un set di strumenti per il reverse engineering e il fuzzing di applicazioni basate su Protobuf
Protobuf è un formato di serializzazione sviluppato da Google e utilizzato in un numero crescente di applicazioni Android, web, desktop e altro. Consiste in un linguaggio per dichiarare strutture dati, che viene poi compilato in codice o in un altro tipo di struttura a seconda dell'implementazione target.
pbtk (Protobuf toolkit) è un set completo di script, accessibile tramite un'interfaccia grafica unificata, che offre due funzionalità principali:
Estrarre strutture Protobuf da programmi, convertendole in file .proto leggibili, supportando diverse implementazioni:
Modificare, riprodurre e fare fuzzing dei dati inviati a endpoint di rete Protobuf, tramite un'interfaccia grafica pratica che permette di modificare in tempo reale i campi di un messaggio Protobuf e visualizzare il risultato.
PBTK richiede Python ≥ 3.5, PySide 6, Python-Protobuf 3 e una manciata di programmi eseguibili (chromium, jad, dex2jar...) per eseguire gli script di estrazione.
Gli utenti Ubuntu possono installarlo usando snap:
$ sudo snap install pbtk
$ pbtk
Gli utenti Archlinux possono installare direttamente tramite il pacchetto:
$ yay -S pbtk-git
$ pbtk
Sulla maggior parte delle altre distribuzioni, conviene eseguirlo direttamente:
# 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
Anche Windows è supportato (con gli stessi moduli richiesti). Una volta avviata la GUI, ti avviserà su ciò che ti manca in base a ciò che provi a fare.
La GUI può essere avviata tramite lo script principale:
pbtk
I seguenti script possono essere usati anche in modo autonomo, senza GUI:
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
Quando installato da snap, i comandi esatti differiscono:
pbtk.jar-extract [-h] input_file [output_dir]
pbtk.from-binary [-h] input_file [output_dir]
pbtk.web-extract [-h] input_url [output_dir]
La GUI può essere avviata tramite lo script principale:
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
I seguenti script possono essere usati anche in modo autonomo, senza GUI:
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
Supponiamo che tu stia facendo reverse engineering di un'applicazione Android. Hai esplorato un po' l'applicazione con il tuo decompilatore preferito e hai capito che trasporta Protobuf come dati POST su HTTPS in modo tipico.
Apri PBTK e vieni accolto in modo significativo:

Il primo passo è ottenere i tuoi .proto in formato testo. Se stai analizzando un'app Android, trascinare un APK e attendere dovrebbe fare il lavoro magico! (a meno che non si tratti di un'implementazione davvero esotica)

Fatto ciò, vai a ~/.pbtk/protos/<nome del tuo APK> (tramite riga di comando o il pulsante in fondo alla schermata di benvenuto per aprire il file browser, come preferisci). Tutti i .proto dell'app sono effettivamente qui.
Tornato al tuo decompilatore, ti sei imbattuto nella classe che costruisce i dati inviati all'endpoint HTTPS che ti interessa. Serializza il messaggio Protobuf chiamando una classe composta da codice generato.

Questa classe dovrebbe avere una corrispondenza esatta nella directory dei tuoi .proto (ad esempio com.foo.bar.a.b corrisponderà a com/foo/bar/a/b.proto). In ogni caso, cercare il suo nome con grep dovrebbe permetterti di farvi riferimento.
Fantastico: il passo successivo è andare al Passo 2, selezionare il file .proto desiderato e compilare alcune informazioni sul tuo endpoint.

Puoi anche fornire alcuni dati Protobuf grezzi di esempio, inviati a questo endpoint, catturati tramite mitmproxy o Wireshark, e che incollerai in forma esadecimale.
Passo 3 è la parte divertente di cliccare pulsanti e vedere cosa succede! Hai una vista ad albero che rappresenta ogni campo nella struttura Protobuf (i campi ripetuti hanno suffisso "+", i campi obbligatori non hanno caselle di controllo).

Basta passare il mouse su un campo per metterlo a fuoco. Se il campo è di tipo intero, usa la rotellina del mouse per incrementarlo/decrementarlo. Le informazioni sull'enumerazione appaiono anche al passaggio del mouse.
Ecco fatto! Puoi determinare il significato di ogni campo con questo. Se hai estratto i .proto da codice minificato, puoi rinominare i campi in base a ciò che noti significano, cliccando sui loro nomi.
Buon reversing! 👌 🎉
PBTK archivia le informazioni .proto estratte in ~/.pbtk/protos/ (o %APPDATA%\pbtk\protos su Windows).
Puoi spostare, rimuovere, rinominare, modificare o cancellare i dati da questa directory direttamente tramite il tuo normale file browser ed editor di testo, è il modo previsto e non interferirà con PBTK.
Gli endpoint basati su HTTP sono archiviati in ~/.pbtk/endpoints/ come oggetti JSON. Questi oggetti sono array di coppie di informazioni richiesta/risposta, che appaiono così:
[{
"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 utilizza internamente due tipi di moduli pluggabili: estrattori e trasporti.
Gli estrattori sono definiti in src/pbtk/extractors/*.py. Sono definiti come un metodo preceduto da un decoratore, in questo modo:
@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.
I trasporti sono definiti in src/pbtk/utils/transports.py. Sono definiti come una classe preceduta da un decoratore, in questo modo:
@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)
I seguenti potrebbero arrivare per le prossime versioni:
Ho cercato di fare del mio meglio per produrre codice ampiamente leggibile e commentato (tranne per le parti che sono per lo più auto-esplicative, come la connessione dei segnali GUI) per la maggior parte dei moduli, così puoi contribuire.
pbtk è rilasciato sotto licenza GNU GPL (Io, qui, ecc.).
Non esiste una regola formalizzata per le maiuscole/minuscole del nome del progetto, la regola è semplicemente seguire il tuo cuore ❤