Comment verrouiller les classes Java compilées pour éviter la décompilation?

96

Comment verrouiller les classes Java compilées pour éviter la décompilation?

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

Beaucoup de gens suggèrent l'obfuscateur, mais ils ne font que 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. Maintenant, dans ce cas, toute personne moyenne de Java peut utiliser JAD pour décompiler le fichier de classe et récupérer facilement la valeur du mot de passe (définie comme constante) ainsi que le 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 ?

jatanp
la source
Même le code natif désassemblé est tout à fait lisible pour certaines personnes de toute façon, vous devrez probablement utiliser un obfuscateur ou un assemblage fait à la main pour le rendre non évident (C ++ commun compilé avec optimisation est suffisamment lisible). Quel que soit le code exécuté sur l'appareil de l'utilisateur, il peut être intercepté. Bien que les exigences en termes de coût / compétence d'une telle interception puissent être assez élevées, par exemple entrer dans le code de puces "inviolables" de carte à puce n'est pas anodin, mais seulement réalisable avec un équipement et une compétence de haut niveau. Avec les classes Java ... je ne me dérangerais pas beaucoup, vous pouvez probablement les chiffrer suffisamment pour détourner les enfants de scripts, pas plus.
Ped7g du

Réponses:

96

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

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

Une autre solution possible ( qui n'exclut pas nécessairement l'obfuscation) consiste à utiliser des fichiers JAR chiffrés et un chargeur de classe personnalisé qui effectue le déchiffrement (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 GCC ou Excelsior JET , par exemple, qui compilent votre code Java directement dans un binaire natif spécifique à la plate-forme.

Dans tous les cas, vous devez vous rappeler que, comme le dit le dicton estonien, "les écluses sont pour les animaux". Ce qui signifie que chaque bit de code est disponible (chargé en mémoire) pendant l'exécution et avec suffisamment de compétences, de détermination et de motivation, les gens peuvent décompiler, déchiffrer et pirater votre code ... Votre travail consiste simplement à rendre le processus aussi inconfortable que vous pouvez et continuez à faire fonctionner la chose ...

Roland Tepp
la source
13
+1 pour "Les serrures sont pour les animaux". Je suppose que le terme approprié ici serait les enfants de script.
Antimoine
Vous voulez dire GCJ, et c'est mort.
Marquis de Lorne
1
Le cryptage des fichiers JAR Componio est également mort. Utilisez plutôt JarProtector .
J.Profi
16

Tant qu'ils ont accès aux données cryptées et au logiciel qui les déchiffre, il n'y a pratiquement aucun moyen de le rendre complètement sécurisé. La façon dont cela a été résolu auparavant est d'utiliser une forme de boîte noire externe pour gérer le cryptage / décryptage, comme les dongles, les 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 faire les choses difficile, pas impossible - à moins que vous ne puissiez lier directement votre produit à la fonctionnalité stockée dans la «boîte noire», comme, par exemple, les serveurs de jeux en ligne.

Erlend Halvorsen
la source
13

Avertissement: je ne suis pas un expert en sécurité.

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

Peut-être que les touches asymétriques pourraient fonctionner:

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

Je ne suis pas sûr, mais je pense que le client peut réellement crypter 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 rechiffrer également.

Vous pouvez conserver une paire de clés publique / privée distincte par client pour vous assurer que vous recevez réellement des informations du bon client - maintenant vous êtes responsable des clés ...

Daren Thomas
la source
2
J'ai déjà utilisé cette technique et cela fonctionne très bien. Cependant, du point de vue des attaques, la première approche serait de simplement modifier le code qui effectue la vérification de licence et de le supprimer. Il y a des choses que vous pouvez faire pour rendre ce vecteur d'attaque plus difficile, mais si vous donnez à l'attaquant le contrôle du matériel, vous êtes voué à l'échec avec un attaquant suffisamment motivé et compétent. En pratique, le but est simplement de garder les gens pour la plupart honnêtes, honnêtes.
Jim Rush
12

Peu importe ce que vous faites, il peut être «décompilé». Heck, vous pouvez simplement le démonter. Ou regardez une image mémoire pour trouver vos constantes. Vous voyez, l'ordinateur a besoin de les connaître, donc votre code en aura besoin aussi.

Que faire à ce sujet?

Essayez de ne pas envoyer la clé en tant que constante codée en dur dans votre code: conservez-la en tant que paramètre par utilisateur. Rendre l'utilisateur responsable de la gestion de cette clé.

Daren Thomas
la source
6

@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 infaillible à ce problème. Même un petit dongle maléfique ne pourrait empêcher cela avec Java.

Mes propres directeurs commerciaux s'inquiètent de cela, et je pense 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. Le fait de se décompiler peut être illégal si votre licence est écrite correctement.

Alors, je dois vous demander, avez-vous vraiment besoin d'une protection renforcée comme vous le souhaitez pour votre application? À quoi ressemble votre clientèle? (Entreprises? Ou les masses de joueurs adolescents, où ce serait plus un problème?)

Stu Thompson
la source
En fait, il existe une solution appropriée et résistante au piratage qui ressemble à un dongle: excelsior-usa.com/blog/excelsior-jet/...
Dmitry Leskov
@DmitryLeskov «résistant au piratage», peut-être. Mais c'est simplement un ralentisseur pour quiconque veut au code. À la fin de la journée, le code d'octet doit s'exécuter sur une plate-forme hôte non chiffrée. Arrêt complet.
Stu Thompson
Vous n'avez pas lu le message auquel j'ai lié. Le bytecode est converti en code CPU du dongle et chiffré. Lorsque l'utilisateur final exécute l'application protégée, ce code crypté est transféré vers le «dongle». Le dongle le déchiffre et l'exécute sur son processeur.
Dmitry Leskov
2
Adolescents professionnels.
odiszapc
3

Si vous recherchez une solution de licence, vous pouvez consulter l' API TrueLicense . Il est basé sur l'utilisation de touches asymétriques. Cependant, cela ne signifie pas que votre application ne peut pas être fissurée. Chaque application peut être craquée avec suffisamment d'efforts. Ce qui est vraiment important, comme l'a répondu Stu , est de déterminer la protection dont vous avez besoin.

hakan
la source
2

Je ne pense pas qu'il existe une méthode antipiratage hors ligne efficace. L'industrie du jeu vidéo a essayé de le constater à 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 lincense, et qu'il n'y ait qu'une seule connexion active par le titulaire de licence à la fois. C'est ainsi que fonctionne World of Warcraft ou Diablo . Même les plus difficiles, il existe des serveurs privés développés pour contourner la sécurité.

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

Telcontar
la source
2

Vous pouvez utiliser le cryptage byte-code sans crainte.

Le fait est que l'article cité ci-dessus «Cracking Java byte-code encryption» contient une erreur de logique. La principale revendication du papier est qu'avant l'exécution, toutes les classes doivent être déchiffrées et passées à la 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échiffrer et à les transmettre ClassLoader. En d'autres termes, si vous êtes dans le JRE standard, vous ne pouvez pas intercepter la defineClass(...)méthode car le java standard n'a pas d'API à cet effet, et si vous utilisez un JRE modifié avec patché ClassLoaderou tout autre «truc de hacker», vous ne pouvez pas le faire car protégé java ne fonctionnera pas du tout et vous n'aurez donc rien à intercepter. Et ce n'est absolument pas grave quel «outil de recherche de patch» est utilisé ou quelle astuce est utilisée par les pirates. Ces détails techniques sont une tout autre histoire.

Yury Bendersky
la source
Comment avez-vous l'intention de détecter exactement une JVM corrigée? Quoi qu'il en soit, tout cela ne fait que rendre les choses un peu plus difficiles.
Antimoine
Vous ne trouvez pas simplement un appel pour defineClass () dans votre lanceur d'applications? Lorsque vous effectuez cet appel, vous devez quand même remettre un tableau d'octets déchiffrés. N'est-ce pas un autre point où la source d'origine pourrait fuir?
Ascendant
4
Je ne suis pas vraiment d'accord avec cette réponse. Pour moi, cela ressemble à: "Question: Quelle est la façon la plus simple de trouver Pi? Réponse: Prenez 2 * Pi et divisez par deux." Je ne suis pas en désaccord avec l'idée, mais pourriez-vous inclure plus de détails? Par exemple, vous attendez-vous à ce que le programme principal soit écrit en pur java? Cela inclut-il le code qui recherche des modifications?
Patrick M
-1

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

R: Le problème de la prévention de la décompilation du code d'octet 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 novices continuent de penser à des moyens nouveaux et intelligents 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 reformulée dans les forums de discussion.

L'extrême facilité avec laquelle les fichiers Java .class peuvent être reconstruits en sources Java qui ressemblent étroitement aux originaux a beaucoup à voir avec les objectifs et les compromis de conception de code octet Java. Entre autres choses, le code d'octet Java a été conçu pour la compacité, l'indépendance de la plate-forme, la mobilité du réseau et la facilité d'analyse par des interpréteurs de code d'octet et des 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 de post-compilation, vous pouvez masser les données .class pour rendre le code d'octet plus difficile à lire lorsqu'il est 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éthode fonctionnent bien pour la première, et la manipulation du flux de contrôle pour créer des structures de contrôle qu'il n'est pas possible de représenter via la syntaxe Java fonctionnent bien pour la seconde. Les obfuscateurs commerciaux les plus réussis utilisent un mélange de ces techniques et d'autres.

Malheureusement, les deux approches doivent en fait changer le code que la JVM exécutera, et de nombreux utilisateurs craignent (à juste titre) que cette transformation puisse ajouter de nouveaux bogues à leurs applications. En outre, le changement de nom de méthode et de champ peut entraîner l'arrêt des appels de réflexion. La modification des noms de classe et de package réels peut casser plusieurs autres API Java (JNDI (Java Naming and Directory Interface), fournisseurs d'URL, etc.). Outre les 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 pile d'exceptions d'origine peut devenir difficile.

Ensuite, il y a la possibilité de masquer le code source Java d'origine. Mais fondamentalement, cela pose un ensemble similaire de problèmes. Crypter, pas obscurcir?

Peut-être que ce qui précède vous a fait penser: "Eh bien, et si au lieu de manipuler du code d'octet je crypte toutes mes classes après compilation et les décrypte à la volée dans la JVM (ce qui peut être fait avec un chargeur de classe personnalisé)? Ensuite, la JVM exécute mon le code d'octet original et pourtant il n'y a rien à décompiler ou à désosser, non? "

Malheureusement, vous vous trompez, à la fois en pensant que vous avez été le premier à avoir cette idée et en pensant que cela fonctionne réellement. Et la raison n'a rien à voir avec la force de votre schéma de cryptage.

S Harish Morampudi
la source