Pergunta

Como bloqueio classes Java compiladas para evitar a descompilação?

Sei que este deve ser um tema muito bem discutido na Internet, mas não consegui chegar a nenhuma conclusão após referi-los.

Muitas pessoas sugerem ofuscador, mas apenas renomeiam classes, métodos e campos com sequências de caracteres difíceis de lembrar, mas e os valores constantes sensíveis?

Por exemplo, você desenvolveu o componente de criptografia e descriptografia com base em uma técnica de criptografia baseada em senha.Agora, neste caso, qualquer pessoa comum em Java pode usar JAD para descompilar o arquivo de classe e recuperar facilmente o valor da senha (definido como constante), bem como sal e por sua vez pode descriptografar os dados escrevendo pequenos programas independentes!

Ou esses componentes sensíveis deveriam ser construídos em código nativo (por exemplo, VC++) e chamá-los via JNI?

Foi útil?

Solução

Alguns dos ofuscadores de bytecode Java mais avançados fazem muito mais do que apenas alterar nomes de classes. Zelix KlassMaster, por exemplo, também pode embaralhar o fluxo do seu código de uma forma que o torna muito difícil de acompanhar e funciona como um excelente otimizador de código...

Além disso, muitos dos ofuscadores também são capazes de embaralhar suas constantes de string e remover código não utilizado.

Outra solução possível (não necessariamente excluindo a ofuscação) é usar arquivos JAR criptografados e um carregador de classe personalizado que faz a descriptografia (de preferência usando uma biblioteca de tempo de execução nativa).

Terceiro (e possivelmente oferecendo a proteção mais forte) é usar compiladores nativos antecipados como CCG ou JATO Excelsior, por exemplo, que compila seu código Java diretamente em um binário nativo específico da plataforma.

Em qualquer caso, você deve lembrar que, como diz o ditado em estoniano, “fechaduras são para animais”.O que significa que cada pedaço de código está disponível (carregado na memória) durante o tempo de execução e com habilidade, determinação e motivação suficientes, as pessoas podem e irão descompilar, desembaralhar e hackear seu código...Seu trabalho é simplesmente tornar o processo o mais desconfortável possível e ainda assim manter a coisa funcionando...

Outras dicas

Contanto que eles tenham acesso aos dados criptografados e ao software que os descriptografa, basicamente não há como tornar isso completamente seguro.A maneira como isso foi resolvido antes é usar alguma forma de caixa preta externa para lidar com criptografia/descriptografia, como dongles, servidores de autenticação remota, etc.Mas mesmo assim, dado que o usuário tem acesso total ao seu próprio sistema, isso só torna as coisas difíceis, não impossíveis - a menos que você possa vincular seu produto diretamente à funcionalidade armazenada na "caixa preta", como, digamos, servidores de jogos online. .

Isenção de responsabilidade:Não sou um especialista em segurança.

Isso parece uma má ideia:Você está permitindo que alguém criptografe coisas com uma chave 'oculta' que você fornece a ele.Não creio que isso possa ser tornado seguro.

Talvez chaves assimétricas possam funcionar:

  • implantar uma licença criptografada com uma chave pública para descriptografar
  • deixe o cliente criar uma nova licença e enviá-la para você para criptografia
  • enviar uma nova licença de volta ao cliente.

Não tenho certeza, mas acredito que o cliente possa criptografar a chave de licença com a chave pública que você forneceu a ele.Você pode então descriptografá-lo com sua chave privada e criptografá-lo novamente.

Você pode manter um par de chaves pública/privada separado por cliente para ter certeza de que está realmente recebendo as coisas do cliente certo - agora você são responsáveis ​​pelas chaves...

Não importa o que você faça, ele pode ser 'descompilado'.Caramba, você pode simplesmente desmontá-lo.Ou consulte um despejo de memória para encontrar suas constantes.Veja bem, o computador precisa conhecê-los, então seu código também precisará.

O que fazer em relação a isto?

Tente não enviar a chave como uma constante codificada em seu código:Mantenha-a como uma configuração por usuário.Torne o usuário responsável por cuidar dessa chave.

@jatanp:ou melhor ainda, eles podem descompilar, remover o código de licenciamento e recompilar.Com Java, eu realmente não acho que exista uma solução adequada e à prova de hackers para esse problema.Nem mesmo um pequeno dongle malvado poderia evitar isso com Java.

Meus próprios gerentes de negócios se preocupam com isso e eu penso demais.Mas, novamente, vendemos nosso aplicativo para grandes empresas que tendem a cumprir as condições de licenciamento – geralmente um ambiente seguro graças aos contadores e advogados.O próprio ato de descompilar pode ser ilegal se sua licença estiver escrita corretamente.

Então, eu tenho que perguntar, você realmente precisa de proteção reforçada como você está procurando para sua aplicação?Como é sua base de clientes?(Empresas?Ou as massas de jogadores adolescentes, onde isso seria mais problemático?)

Se você está procurando uma solução de licenciamento, você pode conferir o API TrueLicense.Baseia-se no uso de chaves assimétricas.No entanto, isso não significa que seu aplicativo não possa ser quebrado.Cada aplicativo pode ser quebrado com bastante esforço.O que é realmente importante é, como Stu respondeu, descobrindo quão forte proteção você precisa.

Não creio que exista nenhum método antipirataria offline eficaz.A indústria dos videojogos tentou descobrir isso muitas vezes e os seus programas sempre foram crackeados.A única solução é que o programa seja executado online conectado aos seus servidores, para que você possa verificar a chave do lincense, e que haja apenas uma conexão ativa do licenciado por vez.É assim Mundo de Warcraft ou Diabo funciona.Mesmo que existam servidores privados desenvolvidos para eles contornarem a segurança.

Dito isto, não acredito que empresas de médio/grande porte usem software copiado ilegalmente, porque o custo da licença para elas é mínimo (talvez eu não saiba quanto você vai cobrar pelo seu programa) em comparação com o custo de uma versão de teste.

Você pode usar criptografia de código de bytes sem medo.

O fato é que o artigo citado acima “Cracking Java byte-code encryption” contém uma falácia lógica.A principal afirmação do jornal é antes de executar todas as classes devem ser descriptografadas e passadas para o ClassLoader.defineClass(...) método.mas isso não é verdade.

A suposição perdida aqui é desde que estejam sendo executados em ambiente de tempo de execução java autêntico ou padrão.Nada pode obrigar o aplicativo Java protegido não apenas a iniciar essas classes, mas até mesmo descriptografá-las e passá-las para ClassLoader.Em outras palavras, se você estiver no JRE padrão, não poderá interceptar defineClass(...) método porque o java padrão não possui API para essa finalidade, e se você usar JRE modificado com patch ClassLoader ou qualquer outro “truque de hacker”, você não pode fazer isso porque o aplicativo Java protegido não funcionará e, portanto, você não terá nada para interceptar.E absolutamente não importa qual “localizador de patch” é usado ou qual truque é usado pelos hackers.Esses detalhes técnicos são uma história bem diferente.

P:Se eu criptografar meus arquivos .class e usar um carregador de classe personalizado para carregá-los e descriptografá-los rapidamente, isso impedirá a descompilação?

A:O problema de evitar a descompilação do código de bytes Java é quase tão antigo quanto a própria linguagem.Apesar de uma série de ferramentas de ofuscação disponíveis no mercado, os programadores Java novatos continuam a pensar em maneiras novas e inteligentes de proteger sua propriedade intelectual.Nesta edição de perguntas e respostas sobre Java, dissipo alguns mitos em torno de uma ideia frequentemente repetida em fóruns de discussão.

A extrema facilidade com que os arquivos Java .class podem ser reconstruídos em fontes Java que se assemelham muito aos originais tem muito a ver com os objetivos e compensações do design do código de bytes Java.Entre outras coisas, o código de bytes Java foi projetado para ser compacto, independente de plataforma, mobilidade de rede e facilidade de análise por interpretadores de código de bytes e compiladores dinâmicos JIT (just-in-time)/HotSpot.Indiscutivelmente, os arquivos .class compilados expressam a intenção do programador de forma tão clara que poderiam ser mais fáceis de analisar do que o código-fonte original.

Várias coisas podem ser feitas, se não para evitar completamente a descompilação, pelo menos para torná-la mais difícil.Por exemplo, como uma etapa pós-compilação, você pode massagear os dados .class para tornar o código de bytes mais difícil de ler quando descompilado ou mais difícil de descompilar em código Java válido (ou ambos).Técnicas como realizar sobrecarga extrema de nomes de métodos funcionam bem para o primeiro, e manipular o fluxo de controle para criar estruturas de controle que não são possíveis de representar por meio da sintaxe Java funcionam bem para o último.Os ofuscadores comerciais mais bem-sucedidos usam uma combinação dessas e de outras técnicas.

Infelizmente, ambas as abordagens devem realmente alterar o código que a JVM executará, e muitos usuários temem (com razão) que essa transformação possa adicionar novos bugs às suas aplicações.Além disso, a renomeação de métodos e campos pode fazer com que as chamadas de reflexão parem de funcionar.Alterar nomes reais de classes e pacotes pode quebrar várias outras APIs Java (JNDI (Java Naming and Directory Interface), provedores de URL, etc.).Além dos nomes alterados, se a associação entre os deslocamentos do código de bytes da classe e os números das linhas de origem for alterada, a recuperação dos rastreamentos de pilha de exceções originais poderá se tornar difícil.

Depois, há a opção de ofuscar o código-fonte Java original.Mas fundamentalmente isto causa um conjunto semelhante de problemas.Criptografar, não ofuscar?

Talvez o que foi dito acima tenha feito você pensar: "Bem, e se, em vez de manipular o código de bytes, eu criptografasse todas as minhas classes após a compilação e as descriptografasse rapidamente dentro da JVM (o que pode ser feito com um carregador de classe personalizado)?Então a JVM executa meu código de bytes original e ainda assim não há nada para descompilar ou fazer engenharia reversa, certo?"

Infelizmente, você estaria errado, tanto ao pensar que foi o primeiro a ter essa ideia quanto ao pensar que ela realmente funciona.E o motivo não tem nada a ver com a força do seu esquema de criptografia.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top