Voltar às atualizações
New releaseAug 21, 2026

pbtk v1.1.3

Um conjunto de ferramentas para engenharia reversa e fuzzing de aplicativos baseados em Protobuf

Compartilhar

pbtk - Engenharia reversa de aplicativos Protobuf

Protobuf é 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.

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:

$ yay -S pbtk-git
$ pbtk

Na maioria das outras distribuições, você vai querer executá-lo diretamente:

# 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:

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:

A tela de boas-vindas

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)

Tela de conclusão

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.

Seu descompilador

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.

Formulário de criação de 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).

Formulário de criação de endpoint

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:

[{
    "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:

@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:

@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 (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 ❤

Categorias