Como saber se um PDF foi editado

O que um PDF registra sobre o próprio histórico, onde ler isso e o que cada achado prova, e o que não prova.

Um PDF guarda recibos: quando foi gravado, o que o gravou, quantas vezes foi salvo e quais objetos um salvamento posterior substituiu. A maior parte disso sobrevive à edição, porque a maioria dos editores não limpa. Esta página percorre as verificações à mão e depois a versão automatizada.

Nenhuma verificação desta página emite veredicto: todas terminam no mesmo lugar: pedir o arquivo original a quem o emitiu.
1 · PROPRIEDADES DO DOCUMENTO O Producer nomeia ferramenta de edição? um fato que merece explicação 2 · CONTAGEM DE REVISÕES Alguma revisão trocou conteúdo de página? o que o documento exibe mudou 3 · SE HOUVER ASSINATURA Há bytes fora do /ByteRange assinado? esses bytes não estão protegidos vá ao emissor: peça o arquivo original Um cliente genuíno consegue baixar de novo; o segundo envio costuma ser mais informativo que o primeiro.

A linguagem importa aqui. Nenhuma dessas verificações prova fraude. Elas estabelecem fatos ("este arquivo foi gravado duas vezes", "duas ferramentas diferentes mexeram nos metadados"), e fatos têm explicações legítimas além das maliciosas. A Tamperlens reporta sinais de risco, não veredictos, e você deveria fazer o mesmo ao relatar isso para alguém.

1. Leia as propriedades do documento

A verificação mais barata, disponível em qualquer leitor de PDF. No Acrobat fica em Arquivo → Propriedades; no Preview, Ferramentas → Mostrar Inspetor; num visualizador de navegador, geralmente em Propriedades do documento no menu da barra de ferramentas. Você está olhando quatro campos do dicionário Info do arquivo: /Producer, /Creator, /CreationDate e /ModDate.

/Producer é o campo interessante. Ele nomeia a biblioteca ou o aplicativo que fisicamente gravou os bytes. Um extrato bancário produzido por um sistema central de banco normalmente carrega a string de uma biblioteca de servidor: uma variante de iText, PDFlib, Prawn, wkhtmltopdf, ReportLab ou Quartz. Se em vez disso ele diz iLovePDF, Smallpdf, Sejda ou PDFescape, o arquivo passou por uma ferramenta que recebe um PDF existente e escreve um novo. Se ele diz Adobe Photoshop ou Microsoft: Print To PDF, o documento foi criado em uma ferramenta que o pipeline de um banco não usaria. Nenhum dos dois é prova de nada, mas ambos são fatos que merecem explicação.

A ressalva óbvia: esses campos são strings. Qualquer pessoa capaz de editar um PDF pode editá-los, e alguns editores os removem por completo. Um Producer ausente já é levemente interessante por si só: geradores automáticos quase sempre se identificam, mas sozinho é evidência fraca. Metadados são a primeira verificação, nunca a última; veja o tratamento mais profundo em forense de metadados de PDF.

2. Compare o dicionário Info com o XMP

Quase todo PDF moderno carrega metadados duas vezes: uma no dicionário Info do trailer e outra num pacote XMP embutido, um bloco XML, geralmente armazenado sem compressão, que dá para ler num editor de texto. Uma única ferramenta gravando o arquivo uma única vez preenche os dois repositórios de forma consistente. Editores de consumo, com muita frequência, atualizam um e deixam o outro desatualizado.

Encontre o pacote XMP

strings statement.pdf | grep -A40 '<x:xmpmeta'
Nada no formato mantém os dois repositórios sincronizados: se eles concordam, é porque uma ferramenta só escreveu os dois.
dicionário Info · no trailer pacote XMP · fluxo do catálogo /Producerpdf:Producer /Creatorxmp:CreatorTool /CreationDatexmp:CreateDate /ModDatexmp:ModifyDate deve bater deve bater deve bater deve bater Uma divergência significa que ao menos um dos dois foi gravado por outra ferramenta.

Divergência indica "mais de um escritor", não um falsificador: pipelines de várias etapas (app de design → destilador → pós-processador) produzem isso de forma legítima e rotineira.

A versão mais forte desse achado é quando os dois repositórios discordam sobre qual ferramenta tocou o arquivo e apenas um deles nomeia um editor. O outro repositório não registrou nada, então a divergência é o único motivo pelo qual aquela ferramenta é visível. Pipelines de publicação em múltiplas etapas (app de design → distiller → pós-processador) produzem divergência simples de forma legítima e rotineira, então trate um simples descompasso como uma pergunta, não como uma resposta.

3. Interprete CreationDate e ModDate corretamente

Datas de PDF se parecem com D:20260104100200+01'00': ano, mês, dia, hora, minuto, segundo e, por fim, um deslocamento UTC com sinal. Três coisas valem a conferência, e nenhuma delas é "o ModDate é posterior ao CreationDate", que é o caso normal de qualquer arquivo salvo.

O que vale conferir não é "o ModDate é posterior ao CreationDate": isso é o caso normal de qualquer arquivo salvo, e sim as três ordens que um gerador funcionando não produz.
prefixo ano mês dia hora min seg deslocamento UTC D: 2026 01 04 10 02 00 +01'00' ModDate antes do CreationDate impossível num gerador datas no futuro desvio de relógio explica minutos, não meses deslocamento além de ±14:00 uma string digitada à mão Um documento com /ModDate e uma única revisão foi reescrito por inteiro, não atualizado incrementalmente. Os dois são edições, com rastros diferentes.

A ausência de um /ModDate não prova nada. Ele é trivialmente removível.

  • ModDate anterior ao CreationDate. Impossível num gerador funcionando corretamente. Significa que os timestamps foram definidos por algo que não é o pipeline que gravou o documento, ou editados diretamente.
  • Datas no futuro. Desvio de relógio explica minutos, não meses.
  • Um deslocamento UTC impossível. Nenhum fuso horário real passa de ±14:00. Um deslocamento +25'00' é uma string digitada à mão.

Também vale notar: um documento com /ModDate mas apenas uma revisão foi reescrito por inteiro, não atualizado incrementalmente. Ambos são edições; apenas deixam rastros diferentes. A ausência de um ModDate não prova nada. Ele é trivialmente removível.

4. Conte as revisões

Esta é a verificação que não depende de nenhuma string que um falsificador possa redigitar, e é o motivo pelo qual a forense de PDF funciona. O PDF suporta atualização incremental: em vez de reescrever um arquivo, uma ferramenta pode anexar ao final novos objetos, uma nova seção de referência cruzada, um novo trailer e um novo %%EOF. Os bytes antigos ficam onde estavam. Um arquivo salvo três vezes pode literalmente conter as três versões.

O peso não está em ter três revisões, e sim em uma delas reescrever um objeto de conteúdo que já existia.
%%EOF %%EOF %%EOF revisão 1 · original revisão 2 · anexada revisão 3 · anexada 12 0 obj 12 0 obj substitui O objeto 12 carrega o fluxo de conteúdo de uma página, e a entrada mais nova vence. O que o documento exibe mudou depois de ele ter sido gerado. Se a revisão só acrescentasse objetos novos, a aparência não teria mudado.

Assinar, preencher um AcroForm, anotar e carimbar também anexam revisões, por isso a contagem sozinha é um sinal de força média, e a pergunta com peso é o que a revisão posterior alterou.

Conte os marcadores de fim de arquivo e os ponteiros de referência cruzada

$ grep -c '%%EOF' statement.pdf
2
$ grep -abo 'startxref' statement.pdf
118842:startxref
184102:startxref

Um único %%EOF significa que o arquivo foi gravado uma vez, na origem, ou salvo de novo por inteiro por uma ferramenta que achatou o histórico. Dois ou mais significam que bytes foram anexados depois que o documento foi concluído pela primeira vez. Cada trailer anexado carrega uma chave /Prev apontando de volta para a seção de referência cruzada anterior, então as revisões formam uma cadeia que dá para percorrer de trás para frente até o original.

Causas legítimas, e há muitas: aplicar uma assinatura digital é, por definição, uma atualização incremental. Preencher um AcroForm também é, assim como adicionar uma anotação ou comentário, ou um passe de linearização de algumas ferramentas. É por isso que a contagem de revisões, sozinha, é um sinal de força média. A pergunta útil é o que a revisão posterior alterou. Se uma segunda revisão reescreve um número de objeto que já existia na primeira e esse objeto guarda dados de página, de fluxo de conteúdo ou de imagem, a aparência renderizada do documento mudou depois de ele ter sido gerado. Isso é um achado bem mais forte do que "foi salvo duas vezes".

5. Leia o par /ID do trailer

O trailer costuma conter um array /ID com duas strings de bytes. A especificação é explícita sobre os papéis: a primeira é um identificador permanente atribuído quando o documento foi criado e nunca deve mudar; a segunda é atualizada pelo aplicativo produtor a cada salvamento.

Olhe o final do arquivo

$ tail -c 400 statement.pdf
trailer
<< /Size 41 /Root 1 0 R /Info 9 0 R
   /ID [<8f2c...a91b> <41de...77c0>] >>
startxref
184102
%%EOF
O próprio formato mantém um marcador de alteração: o primeiro elemento é fixado na criação, o segundo é reescrito a cada gravação.
/ID [<8f2c…a91b> <41de…77c0>] ELEMENTO 1 · PERMANENTE Atribuído quando o documento foi criado. Nunca deve mudar. ELEMENTO 2 · POR GRAVAÇÃO Atualizado pelo aplicativo produtor a cada salvamento. Valores diferentes = o arquivo foi gravado de novo depois de criado.

Duas fraquezas, ditas com todas as letras: alguns geradores minimalistas omitem o /ID por completo (o que remove a verificação em vez de provar algo), e uma ferramenta que reescreve o arquivo inteiro pode gravar os dois elementos com o mesmo valor novo, apagando o rastro.

6. Procure um segundo subconjunto da mesma fonte

Fontes incorporadas em PDFs geralmente entram como subconjuntos (subsets): só os glifos que o documento realmente usa são incluídos, e o nome da fonte ganha um prefixo de seis letras maiúsculas mais um sinal de adição, como ABCDEF+Helvetica. O prefixo é arbitrário; o que importa é que um gerador que grava um documento uma única vez reúne todos os glifos de que precisa para um tipo em um subconjunto.

Liste os nomes das fontes incorporadas

$ strings statement.pdf | grep -o '/BaseFont *[^ /]*' | sort -u
/BaseFont /ABCDEF+Helvetica
/BaseFont /QWERTY+Helvetica
Dois prefixos para a mesma tipografia significam que os glifos dela foram incorporados em duas ocasiões distintas: o rastro que sobrevive mesmo quando os metadados foram apagados.
escrito numa passada texto acrescentado depois /ABCDEF+Helvetica um subconjunto, um prefixo: todos os glifos de que o documento precisa, reunidos de uma vez. /ABCDEF+Helvetica /QWERTY+Helvetica mesma fonte base, dois momentos de incorporação. As seis letras do prefixo são arbitrárias; o que importa é a quantidade de prefixos.

Causas legítimas: um documento montado pela fusão de PDFs de fontes diferentes carrega múltiplos subconjuntos de um tipo comum, assim como um arquivo em que uma anotação de assinatura ou de carimbo trouxe a própria fonte. Leia este sinal junto com o histórico de revisões.

7. Se estiver assinado, verifique o que a assinatura cobre

O /ByteRange de um campo de assinatura é um array de pares deslocamento/comprimento que nomeia exatamente quais bytes do arquivo a assinatura protege: normalmente tudo, exceto o buraco onde a própria assinatura fica. Se o último byte coberto não é o último byte do arquivo, a diferença foi anexada depois da assinatura e não está protegida por ela.

A assinatura cobre um intervalo de bytes nomeado no próprio arquivo; o que estiver depois do último byte coberto entrou depois dela.
/ByteRange [0 8420 42840 15680] trecho 1 coberto trecho 2 coberto /Contents fora último byte coberto Você compara dois números inteiros: onde a cobertura termina e onde o arquivo termina. A diferença não está protegida pela assinatura.

São duas perguntas separadas. "A matemática da assinatura valida?" exige o certificado e um repositório de confiança. "Existem bytes fora do intervalo assinado?" exige apenas o arquivo. E bytes fora do intervalo não são automaticamente ilegítimos: fluxos com mais de uma assinatura os produzem por construção.

Este é o achado estrutural isolado mais forte disponível num PDF, e é legível sem nenhuma criptografia: você compara dois números. Note as duas perguntas separadas. "A matemática da assinatura valida?" exige o certificado e um repositório de confiança. "Existem bytes fora do intervalo assinado?" exige apenas o arquivo. Um visualizador pode alegremente reportar uma assinatura válida enquanto exibe conteúdo que a assinatura nunca cobriu. É por isso que alguns visualizadores mostram "assinado, com alterações posteriores" e os usuários clicam sem ler.

O que a verificação manual não pega

As verificações acima são reais e, para um único arquivo suspeito, muitas vezes bastam. O que elas não conseguem fazer:

  • Correlacionar. Individualmente, cada achado é fraco. O sinal que merece ação é um editor de PDF na cadeia de ferramentas e uma segunda revisão que sobrescreve conteúdo de página. Correlacionar à mão trinta extratos por dia não é um trabalho que alguém faça bem.
  • Enxergar dentro de estruturas comprimidas. Streams de referência cruzada e streams de objetos (PDF 1.5+) são comprimidos com Flate. O grep não consegue lê-los, então uma contagem ingênua de %%EOF é apenas um piso para o número real de revisões.
  • Analisar o conteúdo da página. Saber se uma página é um escaneamento de página inteira com um punhado de glifos vetoriais visíveis desenhados por cima (em oposição a uma camada de OCR invisível, que é normal), exige percorrer o fluxo de conteúdo e ler os modos de renderização de texto.
  • Ser consistente. Dois analistas chegam a duas conclusões. Uma ferramenta determinística dá a mesma resposta para os mesmos bytes, e é isso que torna uma trilha de auditoria defensável.

Automatizando

A Tamperlens faz exatamente as verificações desta página, mais as que exigem um parser de verdade, e as devolve em JSON. Ela analisa os bytes brutos por conta própria, em vez de se apoiar numa biblioteca de PDF de alto nível, porque bibliotecas normalizam justamente a evidência que importa: carregue e salve de novo um arquivo com a maioria delas e o histórico de revisões desaparece.

Dezenove famílias de sinais rodam em todo documento: atualizações incrementais, divergência de metadados, anomalias de data, rastro do Producer, inconsistência de /ID, anomalias de fontes, páginas híbridas, conteúdo ativo, cobertura da assinatura, integridade da assinatura, permissões da assinatura, dígitos verificadores brasileiros, quebra de saldo corrente, anomalias de glifos, anomalias de extração, avisos de estrutura, exposição de tarja, marcadores de injeção no documento e anomalias em imagens incorporadas. Cada uma retorna uma severidade, um detalhe em linguagem clara e evidência legível por máquina (deslocamentos, números de objeto, as strings de fato observadas). Todas estão documentadas, com as respectivas causas legítimas, no guia de campo.

Os documentos são analisados em memória e nunca gravados em disco. O motor usa só CPU, não chama nenhum serviço de terceiros e é determinístico: os mesmos bytes produzem o mesmo relatório, então dá para fazer testes de regressão contra ele.

Rode estas verificações num PDF editado

Abra a amostra "Editado após a criação": um laudo pré-calculado sobre um PDF que ganhou uma segunda revisão depois de pronto, com a cadeia /Prev percorrida e os objetos substituídos nomeados, que é o passo 4 desta página com a evidência junto. Sem conta, sem cota. O seu próprio arquivo entra no mesmo verificador: o arquivo é enviado por HTTPS, processado em memória e nunca gravado em disco, num servidor em Helsinque, na Finlândia (privacidade). No seu pipeline, uma chave de API com 50 documentos por mês é grátis, guia rápido da API ou crie uma conta.

A Tamperlens reporta sinais de risco, não veredictos de autenticidade. Sinais podem ter causas legítimas; combine-os com a sua própria lógica de decisão.

Leitura relacionada