A primeira vez que ouvi o termo engenharia reversa foi na faculdade, numa conversa de corredor. Um colega procurava uma falha de segurança em um jogo para criar um cheat em um título muito antigo, que já não era mais distribuído. Em um primeiro momento, pensei: “Que ideia maluca! Tentar descompilar o código para identificar uma falha, relatá-la ao desenvolvedor ou até criar um plugin de integração.”
Alguns anos depois, me deparei com um cenário semelhante; desta vez eu é que estava fazendo algo parecido. Precisava realizar uma integração com um sistema legado, sem compatibilidade e sem documentação.
Por isso, deixo aqui algumas dicas de como proteger seu código contra esse tipo de prática, minimizando o risco de vulnerabilidades.
Neste artigo, abordo exclusivamente o ambiente JVM e o ecossistema Java (incluindo Kotlin, Scala, Groovy, Clojure e outras linguagens compatíveis), além de APKs do Android.
Chaves e artefatos
Mesmo usando os melhores algoritmos de criptografia (se você pensou em usar MD5, saiba que ele não é criptografia, e sim um hash fraco; se estiver usando para senhas, troque o quanto antes) e seguindo boas práticas, manter chaves dentro do projeto torna sua aplicação fraca e vulnerável. É comum encontrar o código de criptografia e até a chave pública e a privada ao fazer engenharia reversa de um JAR ou APK.
Ao criar sua aplicação, pense em Security by Design e Security by Default: boas práticas de desenvolvimento seguro que mitigam os principais problemas de segurança.
Como boa prática, utilize vaults para disponibilizar chaves de forma segura. Ferramentas recomendadas: AWS KMS, Azure Key Vault, Google Cloud KMS e HashiCorp Vault.
Não se esqueça da rotação periódica de chaves.
Bibliotecas de terceiros
Na pressão por uma correção, muita gente inclui uma biblioteca nova para resolver rápido, sem a devida due diligence. Isso fere o processo de desenvolvimento seguro e abre espaço para incidentes e, no fim, o barato sai caro.
Uma única biblioteca pode derrubar o ecossistema inteiro. Lembra do Log4j CVE-2021-44228 ? Foi “só” a biblioteca de log, e mesmo assim obrigou empresas do mundo todo a mitigar ou substituir versões afetadas. Onde havia políticas bem definidas, o processo correu melhor; já em equipes que costumam deixar isso de lado, a correção às pressas trocou dependências sem avaliação adequada e acabou criando novos problemas.
Boas práticas: crie políticas de dependências, mantenha uma lista de repositórios permitidos (allowlist) e execute varreduras contínuas por CVEs.
Repositórios falsos ou manipulados
Crackers podem disponibilizar repositórios “gratuitos” de Maven, PyPI, Docker Hub e outros. Eles alteram algumas bibliotecas e imagens, que acabam passando despercebidas; quando percebemos, a máquina já foi comprometida e está minerando criptomoedas.
Boas práticas: utilize repositórios internos, como Nexus ou Artifactory, atuando como proxy, com validação de hash e, se possível, assinatura (GPG/cosign) contra as fontes oficiais. Assim, você garante a integridade dos artefatos antes de promovê-los para uso em produção.

Ferramentas de engenharia reversa
Quando tentei fazer minha primeira análise de engenharia reversa, achei que precisaria aprender assembly, montar bit a bit e lidar com outras coisas complexas. Na prática, existem inúmeras maneiras de realizar esse processo e diversas formas de extrair informações.
Vou descrever alguns exemplos e também mostrar um método mais simples para quem está começando ou deseja uma visão prática do assunto:
- CFR (https://www.benf.org/other/cfr/)
- FernFlower (já vem no IntelliJ) (https://github.com/fesh0r/fernflower)
- JD-Gui https://java-decompiler.github.io/
JD-GUI
É o meu preferido: simples e visual. Basta abrir o JAR e ele reconstrói a estrutura da biblioteca. A partir daí, você consegue analisar as classes, verificar as dependências e até personalizar arquivos .class e substituí-los (assunto para outro artigo).

Em alguns cenários, o JD-GUI pode não funcionar, especialmente quando a implantação utiliza um ofuscador. Nesses casos, é melhor recorrer às outras ferramentas citadas para obter uma análise mais precisa do código. Ainda assim, em cerca de 90% dos casos (das bibliotecas que analisei), ele funciona muito bem.