pickletools no Python: analise pickles

Publicado em: 05/08/2026
Tempo de leitura: 7 minutos
Monitor com código binário representando análise de opcodes pickle com pickletools no Python

O formato pickle representa objetos Python como uma sequência de instruções. Carregar um arquivo com pickle.load() executa essas instruções e pode importar funções ou chamar construtores, por isso dados não confiáveis representam risco de execução de código. O módulo pickletools no Python desmonta o fluxo em opcodes legíveis sem executar o pickle, ajudando a estudar protocolos, investigar arquivos e otimizar serializações.

Neste guia, você aprenderá a usar a interface de terminal, dis(), genops() e optimize(), além de reconhecer limites de segurança. O conteúdo complementa nossos artigos sobre pickle no Python, bytecode com dis, shelve, traceback e comparação de arquivos.

Por que pickle exige cuidado

Pickle não é apenas um contêiner passivo de dados. O fluxo contém instruções para reconstruir objetos e pode referenciar globals, callables e mecanismos de redução.

import pickle

with open("dados.pickle", "rb") as arquivo:
    objeto = pickle.load(arquivo)

Esse código é seguro somente quando o arquivo vem de uma fonte totalmente confiável e sua integridade está protegida. Nunca carregue um upload, anexo ou arquivo baixado aleatoriamente.

O papel de pickletools

Pickletools interpreta a estrutura do formato e exibe seus opcodes sem executar as operações de reconstrução.

A documentação oficial de pickletools informa que o módulo é voltado principalmente a desenvolvedores do pickle e ferramentas de baixo nível, mas suas funções também são úteis em auditoria e aprendizado.

Criar um pickle de teste

import pickle

conteudo = {
    "nome": "Ana",
    "pontos": [10, 20, 30],
}

dados = pickle.dumps(
    conteudo,
    protocol=pickle.HIGHEST_PROTOCOL,
)

with open("exemplo.pickle", "wb") as arquivo:
    arquivo.write(dados)

Use dados criados localmente para aprender. Não execute pickle.loads() apenas para descobrir o conteúdo de um arquivo desconhecido.

Desmontar pela linha de comando

python -m pickletools exemplo.pickle

A saída mostra posição, byte do opcode, nome, argumento e informações adicionais. No final, aparece o maior protocolo exigido pelas instruções encontradas.

pickletools versus python -m pickle

python -m pickle carrega o objeto para mostrar sua representação. Isso executa o fluxo e não deve ser usado em arquivos não confiáveis.

python -m pickletools desmonta o formato e é a opção mais segura para inspeção estrutural. Ainda assim, limite tamanho e tempo ao processar entradas hostis.

Anotar cada opcode

A opção -a adiciona descrições curtas.

python -m pickletools -a exemplo.pickle

A anotação ajuda a entender o efeito de operações como PROTO, FRAME, MARK, MEMOIZE, BINUNICODE e STOP.

Salvar a desmontagem

python -m pickletools \
  -o relatorio.txt \
  exemplo.pickle

Não confunda o relatório textual com uma versão sanitizada do objeto. Ele ainda pode conter strings, nomes e outros dados sensíveis presentes no arquivo.

Controlar indentação

-l define quantos espaços são usados a cada nível iniciado por MARK.

python -m pickletools -l 2 exemplo.pickle

A indentação é apenas visual e não altera o arquivo original.

Vários arquivos e preâmbulo

A opção -p imprime um texto antes de cada arquivo.

python -m pickletools \
  -p '=== próximo pickle ===' \
  a.pickle b.pickle

Isso ajuda a separar relatórios concatenados.

Preservar memo entre arquivos

-m mantém o memo ao desmontar vários fluxos.

python -m pickletools -m parte1.pickle parte2.pickle

Use somente quando os pickles foram produzidos por um processo que compartilha memo de forma compatível. Para arquivos independentes, o padrão separado é mais claro.

Ler de stdin

cat exemplo.pickle | python -m pickletools -

Em pipelines, evite misturar dados binários e logs no mesmo fluxo. Defina limites de tamanho antes de encaminhar uploads.

Usar dis() programaticamente

pickletools.dis() escreve uma desmontagem simbólica em um objeto de arquivo.

import io
import pickletools

saida = io.StringIO()
pickletools.dis(
    dados,
    out=saida,
    annotate=40,
)

print(saida.getvalue())

pickle pode ser bytes ou um objeto de arquivo. out usa sys.stdout por padrão.

Memo programático

O parâmetro memo recebe um dicionário compartilhado entre desmontagens.

memo = {}

pickletools.dis(dados_a, memo=memo)
pickletools.dis(dados_b, memo=memo)

O memo representa objetos já armazenados no protocolo. Compartilhá-lo sem que os fluxos tenham relação pode produzir interpretações incorretas.

Iterar opcodes com genops()

genops() fornece triplas (opcode, argumento, posição).

for opcode, argumento, posicao in pickletools.genops(dados):
    print(
        posicao,
        opcode.name,
        argumento,
    )

O objeto OpcodeInfo contém nome, código, documentação, efeito de pilha, protocolo mínimo e outras informações internas.

Criar um relatório estruturado

def relatorio_pickle(dados: bytes):
    for opcode, argumento, posicao in pickletools.genops(dados):
        yield {
            "posicao": posicao,
            "opcode": opcode.name,
            "protocolo": opcode.proto,
            "argumento": repr(argumento),
        }

Limite o tamanho de repr(argumento), pois strings e blobs podem ser enormes.

Identificar operações sensíveis

Uma auditoria pode sinalizar opcodes relacionados à reconstrução de globals e chamadas.

ALERTAS = {
    "GLOBAL",
    "STACK_GLOBAL",
    "REDUCE",
    "BUILD",
    "OBJ",
    "INST",
    "NEWOBJ",
    "NEWOBJ_EX",
}

for opcode, argumento, posicao in pickletools.genops(dados):
    if opcode.name in ALERTAS:
        print("Atenção:", posicao, opcode.name, argumento)

Uma allowlist ou blocklist de opcodes não torna o unpickle seguro. Combinações, extensões e objetos permitidos ainda podem criar comportamentos perigosos.

Protocolos

Pickle possui várias versões de protocolo. Protocolos mais novos podem usar frames, memoização eficiente e suporte melhor a objetos grandes.

import pickle

for protocolo in range(pickle.HIGHEST_PROTOCOL + 1):
    dados = pickle.dumps({"x": 1}, protocol=protocolo)
    nomes = [op.name for op, _, _ in pickletools.genops(dados)]
    print(protocolo, nomes)

O protocolo não é equivalente à versão do Python, embora versões do interpretador definam quais protocolos são suportados.

PROTO e maior protocolo usado

O opcode PROTO declara uma versão, mas a desmontagem também calcula o maior protocolo exigido pelas operações. Fluxos antigos podem não começar com PROTO.

Ferramentas devem observar a sequência completa, não apenas o primeiro byte.

Frames

Protocolos modernos podem dividir o fluxo com FRAME. Frames ajudam o unpickler a processar blocos e reduzir chamadas de leitura.

Um tamanho de frame declarado não deve levar uma ferramenta a alocar memória ilimitada. Leia entradas em ambiente controlado e imponha tamanho máximo ao arquivo.

Memo

O memo evita serializar repetidamente o mesmo objeto e preserva referências compartilhadas.

lista = []
objeto = [lista, lista]
dados = pickle.dumps(objeto, protocol=4)

pickletools.dis(dados)

A desmontagem mostra armazenamento e recuperação da referência. Isso explica por que os dois itens após unpickle apontam para a mesma lista.

Otimizar com optimize()

pickletools.optimize() remove opcodes PUT não utilizados e devolve um pickle equivalente.

otimizado = pickletools.optimize(dados)

print(len(dados), len(otimizado))

O resultado pode ocupar menos espaço e ser carregado mais rapidamente. Não aplique a função a dados não confiáveis sem limites, e não carregue o resultado para “validar” segurança.

Verificar equivalência em dados confiáveis

original = pickle.loads(dados)
otimizado_objeto = pickle.loads(otimizado)
assert original == otimizado_objeto

Esse teste executa pickle e deve ser feito apenas com dados criados ou autenticados pelo próprio sistema.

Assinar pickles confiáveis

Se uma aplicação realmente precisa armazenar pickle, proteja integridade e autenticidade com HMAC ou assinatura e mantenha a chave separada.

A assinatura impede adulteração detectável, mas não transforma arquivos de terceiros em dados confiáveis. Ela só confirma que o conteúdo foi produzido por uma entidade que possui a chave.

Preferir formatos de dados

Para interoperabilidade ou entrada externa, prefira JSON, MessagePack, Protocol Buffers ou um esquema de banco. Esses formatos representam dados, não instruções arbitrárias de reconstrução Python.

Pickle é apropriado principalmente para comunicação e persistência internas entre componentes confiáveis e compatíveis.

Limites de recurso

Mesmo sem executar opcodes, uma análise pode consumir recursos com arquivos grandes, argumentos extensos ou sequências artificiais.

Imponha tamanho máximo, timeout, limite de opcodes e saída truncada. Para uploads, execute a desmontagem em subprocesso com memória e CPU limitadas.

Exemplo de scanner isolado

from pathlib import Path


def analisar(caminho: Path, limite=10_000_000):
    if caminho.stat().st_size > limite:
        raise ValueError("Arquivo grande demais")

    with caminho.open("rb") as arquivo:
        for indice, (op, arg, pos) in enumerate(
            pickletools.genops(arquivo)
        ):
            if indice > 100_000:
                raise ValueError("Muitos opcodes")
            yield pos, op.name, arg

Abra somente arquivos regulares dentro de uma raiz autorizada e evite seguir symlinks inesperados.

pickletools não valida segurança

A desmontagem ajuda analistas a compreender o fluxo, mas não prova que ele é inofensivo. A semântica final depende dos objetos importados, reducers e código disponível no ambiente.

A regra permanece: nunca faça unpickle de uma fonte não confiável.

Erros frequentes

  • Usar python -m pickle para arquivo desconhecido.
  • Carregar o objeto após desmontar para confirmar conteúdo.
  • Confiar em uma blocklist pequena de opcodes.
  • Compartilhar memo entre arquivos independentes.
  • Gerar relatórios sem truncar argumentos.
  • Tratar optimize como sanitização.
  • Ignorar tamanho e quantidade de operações.
  • Presumir compatibilidade eterna entre versões.

Boas práticas

  • Use pickletools para inspeção não executável.
  • Mantenha arquivos desconhecidos longe de pickle.load.
  • Limite tamanho, tempo, opcodes e saída.
  • Execute análises hostis em subprocesso isolado.
  • Use formatos de dados para interfaces externas.
  • Assine apenas pickles produzidos internamente.
  • Registre protocolo e versão do Python.
  • Teste otimização somente com dados confiáveis.

Conclusão

O módulo pickletools no Python revela as instruções que formam um pickle sem executar seu bytecode. A interface de terminal e dis() produzem desmontagens legíveis, genops() permite análise estruturada e optimize() remove memoizações desnecessárias.

Essa visibilidade ajuda a aprender o formato e investigar arquivos, mas não torna pickle seguro. A proteção real vem de não carregar entradas desconhecidas, impor limites e preferir formatos puramente declarativos nas fronteiras do sistema.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Código-fonte em tela representando análise com tokenize no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    tokenize no Python: analise código-fonte

    Aprenda tokenize no Python para ler tokens, comentários, indentação, codificação, posições e reconstruir código-fonte com segurança.

    Ler mais

    Tempo de leitura: 6 minutos
    05/08/2026
    Desenvolvedor trabalhando em automação de build e compilação de diretórios com compileall no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    compileall no Python: compile diretórios

    Aprenda compileall no Python para compilar diretórios, gerar pyc em paralelo, filtrar arquivos e controlar otimização e invalidação.

    Ler mais

    Tempo de leitura: 7 minutos
    04/08/2026
    Monitor com código binário representando geração de arquivos pyc com py_compile no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    py_compile no Python: gere arquivos pyc

    Aprenda py_compile no Python para gerar arquivos pyc, validar sintaxe e controlar otimização e invalidação por timestamp ou hash.

    Ler mais

    Tempo de leitura: 7 minutos
    04/08/2026
    Editor de código representando correção de tabs e espaços com tabnanny no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    tabnanny no Python: corrija indentação

    Aprenda tabnanny no Python para detectar tabs e espaços ambíguos, verificar projetos e evitar TabError e IndentationError.

    Ler mais

    Tempo de leitura: 7 minutos
    04/08/2026
    Código-fonte e sintaxe representando análise lexical com tokenize no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    tokenize no Python: analise código-fonte

    Aprenda tokenize no Python para analisar tokens, comentários, encoding, posições e reconstruir código-fonte com segurança.

    Ler mais

    Tempo de leitura: 6 minutos
    04/08/2026
    Terminal de programação representando compilação de entradas interativas com codeop no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    codeop no Python: compile entradas interativas

    Aprenda codeop no Python para detectar entradas completas, compilar comandos de REPL e preservar __future__ com segurança.

    Ler mais

    Tempo de leitura: 6 minutos
    04/08/2026