
Um conjunto de ferramentas para engenharia reversa e fuzzing de aplicativos baseados em Protobuf
# pbtk - Engenharia reversa de aplicativos Protobuf
**[Protobuf](https://developers.google.com/protocol-buffers/) é um formato de serialização** desenvolvido pelo Google e usado em um número crescente de aplicativos Android, web, desktop e outros. Consiste em uma **linguagem para declarar estruturas de dados**, que é então compilada para código ou outro tipo de estrutura, dependendo da implementação alvo.
pbtk (*Protobuf toolkit*) é um conjunto completo de scripts, acessível através de uma GUI unificada, que fornece duas funcionalidades principais:
- **Extrair estruturas Protobuf de programas**, convertendo-as de volta para arquivos *.proto* legíveis, suportando várias implementações:
- Todos os principais runtimes Java (base, Lite, Nano, Micro, J2ME), com suporte total ao Proguard *(2026: ainda funciona bem, mas principalmente com APKs antigos)*
- Binários contendo metadados de reflexão embutidos (tipicamente C++, às vezes Java e a maioria das outras ligações) *(2026: ainda funciona bem)*
- Aplicativos web usando o runtime JsProtoUrl. *(2026: precisa de uma atualização)*
- **Editar, repetir e fazer fuzzing de dados** enviados para endpoints de rede Protobuf, através de uma interface gráfica prática que permite editar ao vivo os campos de uma mensagem Protobuf e visualizar o resultado.
<img src="https://assets.kitploit.com/production/public/readmes/3051/860b9306c2be49d204ad562b8bf0abdb831e9f1c9852edda265734fe26be1a2b.png" alt="A GUI do editor pbtk">
## Instalação
O PBTK requer Python ≥ 3.5, PySide 6, Python-Protobuf 3 e alguns programas executáveis (chromium, jad, dex2jar...) para executar os scripts de extração.
Usuários Ubuntu podem instalá-lo usando `snap`:
```
$ sudo snap install pbtk
$ pbtk
```
Usuários Archlinux podem instalar diretamente através do [pacote](https://aur.archlinux.org/packages/pbtk-git/):
```
$ yay -S pbtk-git
$ pbtk
```
Na maioria das outras distribuições, você vai querer executá-lo diretamente:
```tcl
# Para derivados Ubuntu/Debian em teste:
$ sudo apt install python3-pip git openjdk-8-jre python3-qtpy-pyside6
# Em seguida, usando UV:
$ sudo snap install --classic astral-uv
$ uv tool install pbtk
$ pbtk
# Ou usando pipx:
$ sudo apt install pipx
$ pipx install pbtk
$ pbtk
```
O Windows também é suportado (com os mesmos módulos necessários). Depois de executar a GUI, ela deve avisar sobre o que está faltando, dependendo do que você tentar fazer.
## Uso da linha de comando (instalando via gerenciador de pacotes)
A GUI pode ser iniciada através do script principal:
pbtk
Os seguintes scripts também podem ser usados de forma autônoma, sem 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] # Precisa de atualização para funcionar a partir de 2026
Quando instalado via `snap`, os comandos exatos diferem:
pbtk.jar-extract [-h] input_file [output_dir]
pbtk.from-binary [-h] input_file [output_dir]
pbtk.web-extract [-h] input_url [output_dir]
## Uso da linha de comando (local)
A GUI pode ser iniciada através do script principal:
```bash
uv sync # Baixar dependências para a pasta .venv
source .venv/bin/activate # Colocar os scripts locais no $PATH para a sessão atual do shell
uv tool install -e . # Colocar os scripts locais no $PATH permanentemente
pbtk
```
Os seguintes scripts também podem ser usados de forma autônoma, sem 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] # Precisa de atualização para funcionar a partir de 2026
## Fluxo de trabalho típico
Digamos que você está fazendo engenharia reversa de um aplicativo Android. Você explorou um pouco o aplicativo com seu descompilador favorito e descobriu que ele transporta Protobuf como dados POST via HTTPS de forma típica.
Você abre o PBTK e é recebido de forma significativa:

O primeiro passo é obter seus .protos em formato de texto. Se você está mirando um aplicativo Android, soltar um APK e esperar deve fazer o trabalho mágico! (a menos que seja uma implementação realmente exótica)

Feito isso, você vai para `~/.pbtk/protos/<nome do seu APK>` (através da linha de comando ou do botão na parte inferior da tela de boas-vindas para abrir o navegador de arquivos, da forma que preferir). Todos os .protos do aplicativo estão aqui.
De volta ao seu descompilador, você se deparou com a classe que constrói os dados enviados para o endpoint HTTPS que lhe interessa. Ela serializa a mensagem Protobuf chamando uma classe feita de código gerado.

Esta última classe deve ter uma correspondência perfeita dentro do seu diretório .protos (isto é, `com.foo.bar.a.b` corresponderá a `com/foo/bar/a/b.proto`). De qualquer forma, pesquisar seu nome deve permitir referenciá-la.
Isso é ótimo: a próxima coisa é ir para a **Etapa 2**, selecionar o arquivo .proto de entrada desejado e preencher algumas informações sobre seu endpoint.

Você também pode fornecer alguns dados Protobuf brutos de exemplo, que foram enviados para este endpoint, capturados através do mitmproxy ou Wireshark, e que você colará em formato hex.
**Etapa 3** é sobre a parte divertida de clicar em botões e ver o que acontece! Você tem uma visualização em árvore representando cada campo na estrutura Protobuf (campos repetidos são sufixados por "+", campos obrigatórios não têm caixas de seleção).

Apenas passe o mouse sobre um campo para focá-lo. Se o campo for do tipo inteiro, use a roda do mouse para incrementar/decrementar. Informações sobre enum aparecem também ao passar o mouse.
Aqui está! Você pode determinar o significado de cada campo com isso. Se você extraiu .protos de código minificado, pode renomear campos de acordo com o que você percebe que eles significam, clicando em seus nomes.
Feliz engenharia reversa! 👌 🎉
## Armazenamento local de dados
O PBTK armazena informações de .proto extraídas em `~/.pbtk/protos/` (ou `%APPDATA%\pbtk\protos` no Windows).
Você pode mover para dentro, mover para fora, renomear, editar ou apagar dados deste diretório diretamente através do seu navegador de arquivos e editor de texto comuns, é a forma esperada de fazer isso e não interferirá com o PBTK.
Endpoints baseados em HTTP são armazenados em `~/.pbtk/endpoints/` como objetos JSON. Esses objetos são arrays de pares de informações de requisição/resposta, que se parecem com isso:
```javascript
[{
"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"
}
}]
```
## Estrutura do código-fonte
O PBTK usa internamente dois tipos de módulos plugáveis: extratores e transportes.
* Um **extrator** suporta a extração de estruturas .proto de uma implementação ou plataforma Protobuf alvo.
Os extratores são definidos em `src/pbtk/extractors/*.py`. Eles são definidos como um método precedido por um decorador, assim:
```python
@register_extractor(name = 'my_extractor',
desc = 'Extrair estruturas Protobuf de código Foobar (*.foo, *.bar)',
depends={'binaries': ['foobar-decompiler']})
def my_extractor(path):
# Carregar o conteúdo do arquivo de entrada `path` e fazer seu trabalho...
# Em seguida, gerar os .protos extraídos usando um gerador:
for i in do_your_extraction_work():
yield proto_name + '.proto', proto_contents
# Outros tipos de informação podem ser gerados, como informações de endpoint ou progresso a ser exibido.
```
* Um **transporte** suporta uma forma de desserializar, resserializar e enviar dados Protobuf pela rede. Por exemplo, o transporte mais comumente usado são dados POST brutos via HTTP.
Os transportes são definidos em `src/pbtk/utils/transports.py`. Eles são definidos como uma classe precedida por um decorador, assim:
```python
@register_transport(
name = 'my_transport',
desc = 'Protobuf como dados POST brutos',
ui_data_form = 'hex strings'
)
class MyTransport():
def __init__(self, pb_param, url):
self.url = url
def serialize_sample(self, sample):
# Recebemos um exemplo de dados de entrada do usuário.
# Verificar se é válido na forma descrita através do parâmetro "ui_data_form", falhar com uma exceção ou retornar False caso contrário.
# Opcionalmente modificar esses dados antes de retorná-los.
bytes.fromhex(sample)
return sample
def load_sample(self, sample, pb_msg):
# Analisar os dados de entrada no objeto Protobuf fornecido.
pb_msg.ParseFromString(bytes.fromhex(sample))
def perform_request(self, pb_data, tab_data):
# Realizar uma requisição usando a URL e o objeto Protobuf fornecidos, e opcionalmente outros dados laterais específicos do transporte.
return post(url, pb_data.SerializeToString(), headers=USER_AGENT)
```
## Melhorias futuras
O seguinte pode vir em versões futuras:
* Finalização da parte de fuzzing automático.
* Suporte para extração de extensões de código Java.
* Suporte para o runtime JSPB (JavaScript principal).
* Se houver qualquer outra plataforma que você deseje ver suportada, basta abrir uma issue e darei uma olhada.
Tentei fazer o meu melhor para produzir código minuciosamente legível e comentado (exceto para partes que são praticamente autoexplicativas, como conectar sinais da GUI) para a maioria dos módulos, para que você possa contribuir.
## Licenciamento
pbtk é lançado sob a licença [GNU GPL](https://www.gnu.org/licenses/gpl-3.0.html) (eu, por meio deste, etc.).
Não há regra formalizada para o uso de maiúsculas/minúsculas do nome do projeto, a regra é apenas seguir seu coração ❤