Comment verrouiller les classes Java compilées pour empêcher la décompilation ?

StackOverflow https://stackoverflow.com/questions/49379

  •  09-06-2019
  •  | 
  •  

Question

Comment verrouiller les classes Java compilées pour empêcher la décompilation ?

Je sais que ce sujet doit être très bien discuté sur Internet, mais je n'ai pu parvenir à aucune conclusion après y avoir fait référence.

Beaucoup de gens suggèrent un obfuscateur, mais ils se contentent de renommer les classes, les méthodes et les champs avec des séquences de caractères difficiles à retenir, mais qu'en est-il des valeurs constantes sensibles ?

Par exemple, vous avez développé le composant de chiffrement et de déchiffrement basé sur une technique de chiffrement basée sur un mot de passe.Dans ce cas, toute personne Java moyenne peut utiliser JAD pour décompiler le fichier de classe et récupérer facilement la valeur du mot de passe (défini comme constant) ainsi que sel et à son tour peut décrypter les données en écrivant un petit programme indépendant !

Ou ces composants sensibles devraient-ils être construits en code natif (par exemple, VC++) et les appeler via JNI?

Était-ce utile?

La solution

Certains des obfuscateurs de bytecode Java les plus avancés font bien plus que simplement modifier les noms de classes. Maître de classe Zelix, par exemple, peut également brouiller votre flux de code d'une manière qui le rend très difficile à suivre et fonctionne comme un excellent optimiseur de code...

De nombreux obfuscateurs sont également capables de brouiller vos constantes de chaîne et de supprimer le code inutilisé.

Une autre solution possible (n'excluant pas nécessairement l'obscurcissement) consiste à utiliser fichiers JAR cryptés et un chargeur de classe personnalisé qui effectue le décryptage (de préférence en utilisant la bibliothèque d'exécution native).

Troisièmement (et offrant peut-être la protection la plus forte) consiste à utiliser des compilateurs natifs à l'avance comme CCG ou Excelsior JET, par exemple, qui compilent votre code Java directement dans un binaire natif spécifique à la plate-forme.

Dans tous les cas, il ne faut pas oublier que, comme le dit le proverbe estonien, « les serrures sont pour les animaux ».Cela signifie que chaque morceau de code est disponible (chargé en mémoire) pendant l'exécution et qu'avec suffisamment de compétences, de détermination et de motivation, les gens peuvent et vont décompiler, déchiffrer et pirater votre code...Votre travail consiste simplement à rendre le processus aussi inconfortable que possible tout en continuant à faire fonctionner la chose...

Autres conseils

Tant qu’ils ont accès à la fois aux données cryptées et au logiciel qui les déchiffre, il n’y a pratiquement aucun moyen de sécuriser complètement cela.La façon dont ce problème a été résolu auparavant consiste à utiliser une forme de boîte noire externe pour gérer le cryptage/déchiffrement, comme des dongles, des serveurs d'authentification à distance, etc.Mais même dans ce cas, étant donné que l'utilisateur a un accès complet à son propre système, cela ne fait que rendre les choses difficiles, pas impossibles - à moins que vous puissiez lier votre produit directement aux fonctionnalités stockées dans la « boîte noire », comme, par exemple, les serveurs de jeux en ligne. .

Clause de non-responsabilité:Je ne suis pas un expert en sécurité.

Cela semble être une mauvaise idée :Vous laissez quelqu'un chiffrer des éléments avec une clé « cachée » que vous lui donnez.Je ne pense pas que cela puisse être sécurisé.

Peut-être que des clés asymétriques pourraient fonctionner :

  • déployer une licence chiffrée avec une clé publique à décrypter
  • laissez le client créer une nouvelle licence et vous l'envoyer pour cryptage
  • renvoyer une nouvelle licence au client.

Je ne suis pas sûr, mais je pense que le client peut réellement chiffrer la clé de licence avec la clé publique que vous lui avez donnée.Vous pouvez ensuite le déchiffrer avec votre clé privée et le recrypter également.

Vous pouvez conserver une paire de clés publique/privée distincte par client pour vous assurer que vous obtenez réellement les informations du bon client - maintenant toi sont responsables des clés...

Quoi que vous fassiez, il peut être « décompilé ».Bon sang, vous pouvez simplement le démonter.Ou regardez un vidage de mémoire pour trouver vos constantes.Vous voyez, l’ordinateur a besoin de les connaître, donc votre code le devra aussi.

Que faire à ce sujet ?

Essayez de ne pas envoyer la clé sous forme de constante codée en dur dans votre code :Conservez-le comme paramètre par utilisateur.Rendre l'utilisateur responsable de la gestion de cette clé.

@jatanp :ou mieux encore, ils peuvent décompiler, supprimer le code de licence et recompiler.Avec Java, je ne pense pas vraiment qu'il existe une solution appropriée et anti-piratage à ce problème.Même un petit dongle maléfique ne pourrait pas empêcher cela avec Java.

Mes propres responsables commerciaux s'en inquiètent et j'y réfléchis trop.Mais là encore, nous vendons notre application à de grandes entreprises qui ont tendance à respecter les conditions de licence – généralement un environnement sûr grâce aux compteurs de haricots et aux avocats.L'acte de se décompiler peut être illégal si votre licence est écrite correctement.

Alors, je dois demander, est-ce que vraiment avez-vous besoin d’une protection renforcée comme celle que vous recherchez pour votre application ?À quoi ressemble votre clientèle ?(Les entreprises ?Ou le grand public des joueurs adolescents, où cela poserait davantage de problèmes ?)

Si vous recherchez une solution de licence, vous pouvez consulter le API TrueLicense.Il est basé sur l'utilisation de clés asymétriques.Cependant, cela ne signifie pas que votre application ne peut pas être crackée.Chaque application peut être crackée avec suffisamment d’effort.Ce qui est vraiment important, c'est, comme Stu a répondu, en déterminant le niveau de protection dont vous avez besoin.

Je ne pense pas qu’il existe une méthode efficace de lutte contre le piratage hors ligne.L’industrie du jeu vidéo a essayé de le découvrir à plusieurs reprises et ses programmes ont toujours été piratés.La seule solution est que le programme doit être exécuté en ligne connecté à vos serveurs, afin que vous puissiez vérifier la clé de licence, et qu'il n'y ait qu'une seule connexion active par le titulaire de la licence à la fois.C'est ainsi World of Warcraft ou Diablo travaux.Même si cela est difficile, il existe des serveurs privés développés pour contourner la sécurité.

Cela dit, je ne crois pas que les moyennes et grandes entreprises utilisent des logiciels copiés illégaux, car le coût de la licence pour elles est minime (peut-être, je ne sais pas combien vous allez facturer pour votre programme) par rapport à le coût d'une version d'essai.

Vous pouvez utiliser le cryptage par byte-code sans crainte.

Le fait est que l’article cité ci-dessus « Cracker le chiffrement du byte-code Java » contient une erreur logique.La principale affirmation du document est avant d'exécuter toutes les classes doivent être déchiffrées et transmises au ClassLoader.defineClass(...) méthode.Mais ce n'est pas vrai.

L'hypothèse manquée ici est à condition qu'ils s'exécutent dans un environnement d'exécution Java authentique ou standard.Rien ne peut obliger l'application Java protégée non seulement à lancer ces classes mais même à les décrypter et à les transmettre à ClassLoader.En d'autres termes, si vous êtes en JRE standard, vous ne pouvez pas intercepter defineClass(...) car le Java standard n'a pas d'API à cet effet, et si vous utilisez un JRE modifié avec des correctifs ClassLoader ou tout autre « truc de hacker », vous ne pouvez pas le faire car l'application Java protégée ne fonctionnera pas du tout et vous n'aurez donc rien à intercepter.Et peu importe quel « outil de recherche de correctifs » est utilisé ou quelle astuce est utilisée par les pirates.Ces détails techniques sont une tout autre histoire.

Question :Si je chiffre mes fichiers .class et que j'utilise un chargeur de classe personnalisé pour les charger et les déchiffrer à la volée, cela empêchera-t-il la décompilation ?

UN:Le problème de la prévention de la décompilation du byte-code Java est presque aussi ancien que le langage lui-même.Malgré une gamme d'outils d'obscurcissement disponibles sur le marché, les programmeurs Java débutants continuent de réfléchir à de nouvelles façons intelligentes de protéger leur propriété intellectuelle.Dans cet épisode de questions-réponses Java, je dissipe certains mythes autour d'une idée fréquemment ressassée dans les forums de discussion.

L'extrême facilité avec laquelle les fichiers Java .class peuvent être reconstruits en sources Java qui ressemblent beaucoup aux originaux a beaucoup à voir avec les objectifs et les compromis de conception du byte-code Java.Entre autres choses, le byte code Java a été conçu pour être compact, indépendant de la plateforme, mobile du réseau et facile à analyser par les interpréteurs de byte code et les compilateurs dynamiques JIT (juste à temps)/HotSpot.On peut soutenir que les fichiers .class compilés expriment si clairement l'intention du programmeur qu'ils pourraient être plus faciles à analyser que le code source d'origine.

Plusieurs choses peuvent être faites, sinon pour empêcher complètement la décompilation, du moins pour la rendre plus difficile.Par exemple, comme étape post-compilation, vous pouvez masser les données .class pour rendre le code d'octet plus difficile à lire une fois décompilé ou plus difficile à décompiler en code Java valide (ou les deux).Des techniques telles que la surcharge extrême des noms de méthodes fonctionnent bien pour le premier, et la manipulation du flux de contrôle pour créer des structures de contrôle impossibles à représenter via la syntaxe Java fonctionnent bien pour le second.Les obfuscateurs commerciaux les plus performants utilisent un mélange de ces techniques et d’autres.

Malheureusement, les deux approches doivent en fait modifier le code que la JVM exécutera, et de nombreux utilisateurs craignent (à juste titre) que cette transformation puisse ajouter de nouveaux bugs à leurs applications.De plus, le renommage des méthodes et des champs peut empêcher les appels de réflexion de fonctionner.La modification des noms réels de classes et de packages peut interrompre plusieurs autres API Java (JNDI (Java Naming and Directory Interface), fournisseurs d'URL, etc.).En plus des noms modifiés, si l'association entre les décalages de code d'octet de classe et les numéros de ligne source est modifiée, la récupération des traces de la pile d'exceptions d'origine pourrait devenir difficile.

Il existe ensuite la possibilité de masquer le code source Java d'origine.Mais fondamentalement, cela pose un ensemble de problèmes similaires.Chiffrer, pas masquer ?

Peut-être que ce qui précède vous a fait penser : « Eh bien, et si, au lieu de manipuler le code d'octet, je chiffrais toutes mes classes après la compilation et les décryptais à la volée dans la JVM (ce qui peut être fait avec un chargeur de classes personnalisé) ?Ensuite, la JVM exécute mon code d'octet d'origine et pourtant il n'y a rien à décompiler ou à procéder à une ingénierie inverse, n'est-ce pas ?"

Malheureusement, vous auriez tort, à la fois en pensant que vous avez été le premier à avoir eu cette idée et en pensant qu'elle fonctionne réellement.Et la raison n’a rien à voir avec la force de votre système de cryptage.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top