
Un conjunto de herramientas para ingeniería inversa y fuzzing de apps basadas en Protobuf
Protobuf es un formato de serialización desarrollado por Google y utilizado en un número creciente de aplicaciones Android, web, de escritorio y más. Consiste en un lenguaje para declarar estructuras de datos, que luego se compila a código u otro tipo de estructura según la implementación de destino.
pbtk (Protobuf toolkit) es un conjunto completo de scripts, accesible a través de una GUI unificada, que ofrece dos funcionalidades principales:
Extraer estructuras Protobuf de programas, convirtiéndolas de nuevo a .proto legibles, compatible con varias implementaciones:
Editar, reproducir y fuzzear datos enviados a endpoints de red Protobuf, a través de una práctica interfaz gráfica que permite editar en vivo los campos de un mensaje Protobuf y ver el resultado.
PBTK requiere Python ≥ 3.5, PySide 6, Python-Protobuf 3, y un puñado de programas ejecutables (chromium, jad, dex2jar...) para ejecutar los scripts de extracción.
Los usuarios de Ubuntu pueden instalarlo usando snap:
$ sudo snap install pbtk
$ pbtk
Los usuarios de Archlinux pueden instalarlo directamente a través del paquete:
$ yay -S pbtk-git
$ pbtk
En la mayoría de otras distribuciones, querrás ejecutarlo directamente:
# 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 también es compatible (con los mismos módulos requeridos). Una vez que ejecutes la GUI, te advertirá sobre lo que te falta dependiendo de lo que intentes hacer.
La GUI se puede lanzar mediante el script principal:
pbtk
Los siguientes scripts también se pueden usar de forma independiente, sin 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
Cuando se instala desde snap, los comandos exactos difieren:
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 se puede lanzar mediante el script principal:
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
Los siguientes scripts también se pueden usar de forma independiente, sin 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
Supongamos que estás realizando ingeniería inversa de una aplicación Android. Exploraste un poco la aplicación con tu descompilador favorito y descubriste que transporta Protobuf como datos POST sobre HTTPS de forma típica.
Abres PBTK y te recibe de manera significativa:

El primer paso es obtener tus .protos en formato de texto. Si estás analizando una aplicación Android, ¡soltar un APK y esperar debería hacer el trabajo mágico! (a menos que sea una implementación realmente exótica)

Hecho esto, te diriges a ~/.pbtk/protos/<nombre de tu APK> (ya sea a través de la línea de comandos o del botón en la parte inferior de la pantalla de bienvenida para abrir tu explorador de archivos, como prefieras). Todos los .protos de la aplicación están aquí.
De vuelta en tu descompilador, te topaste con la clase que construye los datos enviados al endpoint HTTPS que te interesa. Serializa el mensaje Protobuf llamando a una clase hecha de código generado.

Esta última clase debería tener una coincidencia perfecta dentro de tu directorio .protos (por ejemplo, com.foo.bar.a.b coincidirá con com/foo/bar/a/b.proto). De cualquier manera, buscar su nombre con grep debería permitirte referenciarla.
Eso es genial: lo siguiente es ir al Paso 2, seleccionar tu .proto de entrada deseado y completar algo de información sobre tu endpoint.

También puedes proporcionar algunos datos Protobuf sin procesar de muestra, que fueron enviados a este endpoint, capturados a través de mitmproxy o Wireshark, y que pegarás en forma codificada en hexadecimal.
Paso 3 trata sobre la parte divertida de hacer clic en botones y ver qué sucede. Tienes una vista de árbol que representa cada campo en la estructura Protobuf (los campos repetidos tienen el sufijo "+", los campos requeridos no tienen casillas de verificación).

Simplemente pasa el ratón sobre un campo para enfocarlo. Si el campo es de tipo entero, usa la rueda del ratón para incrementarlo/decrementarlo. La información del enum también aparece al pasar el ratón.
¡Ahí está! Puedes determinar el significado de cada campo con eso. Si extrajiste .protos de código minificado, puedes renombrar los campos según lo que notes que significan, haciendo clic en sus nombres.
¡Feliz ingeniería inversa! 👌 🎉
PBTK almacena la información extraída de .proto en ~/.pbtk/protos/ (o %APPDATA%\pbtk\protos en Windows).
Puedes mover, sacar, renombrar, editar o borrar datos de este directorio directamente a través de tu explorador de archivos y editor de texto habitual, es la forma esperada de hacerlo y no interferirá con PBTK.
Los endpoints basados en HTTP se almacenan en ~/.pbtk/endpoints/ como objetos JSON. Estos objetos son arreglos de pares de información de solicitud/respuesta, que se ven así:
[{
"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 utiliza internamente dos tipos de módulos conectables: extractores y transportes.
Los extractores se definen en src/pbtk/extractors/*.py. Se definen como un método precedido por un decorador, como esto:
@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.
Los transportes se definen en src/pbtk/utils/transports.py. Se definen como una clase precedida por un decorador, como esto:
@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)
Lo siguiente podría llegar en futuras versiones:
He hecho todo lo posible por producir un código completamente legible y comentado (excepto las partes que se explican por sí mismas, como la conexión de señales de la GUI) para la mayoría de los módulos, para que puedas contribuir.
pbtk se publica bajo la licencia GNU GPL (Yo, por la presente, etc.).
No hay una regla formalizada para el uso de mayúsculas y minúsculas en el nombre del proyecto, la regla es solo seguir tu corazón ❤