Le décompilateur JAD


précédentsommairesuivant

I. Qu'est-ce qu'un décompilateur

I-A. Petit rappel théorique

Contrairement à des langages tels que le C ou le C++, qui sont des langages compilés, Java fait partie d'une autre famille qu'on appelle langages semi-compilés.
C'est à dire que le compilateur Java ne produira pas du code binaire, qui aurait pu être compris directement par le système d'exploitation, mais un code intermédiaire communément appelé bytecode.

La conséquence de cela est qu'un programme Java n'est pas "autoexécutable", et qu'il a besoin d'une machine virtuelle Java, dont le rôle est d'interpréter ce bytecode et d'éxécuter les appels systèmes correspondants.
Ce bytecode est stocké dans les fichiers .class que génère le compilateur Java.

I-B. A quoi ressemble du bytecode ?

Afin de mieux comprendre, nous allons compiler la classe com.developpez.hikage.bytecode.ByteCode, et visualiser le fichier .class grâce à un outil.
Dans ce screenshot, on peut voir différentes sections, telles que Fields, Constants, Methods, Interfaces ...

ByteCode dans Bytecode Viewer
ByteCode dans Bytecode Viewer

Etudions un peu le bytecode de la méthode maMethode :

Bytecode de maMethode
Sélectionnez

0 ldc #23 <Visitez Developpez.com>
2 astore_1
3 iconst_0 
4 istore_2 
5 goto 18 (+13) 
8 getstatic #25 <java/lang/System.out>
11 aload_1
12 invokevirtual #31<java/io/PrintStream.println>
15 iinc 2 by 1
18 iload_2 
19 bipush 10 
21 if_icmplt 8 (-13) 
24 return
                

Ce qui donne comme suite d'éxécution :

  • ligne 0 : chargement de la constante 23 ( une chaine "Visitez Developpez.com" ) sur la pile
  • ligne 2 : stockage de la variable de la pile ( donc la chaine précedente ) dans la première variable locale
  • ligne 3 : chargement de la valeur entière 0 sur la pile
  • ligne 4 : stockage de la variable de la pile ( donc la valeur 0 ) dans la deuxième variable locale
  • ligne 5 : saut à la ligne 18
  • ligne 18 : chargement d'une valeur entière provenant de la variable 2 vers la pile
  • ligne 19 : chargement de la valeur 10 sur la pile ( valeur sur la pile : 10 suivi de la valeur de la variable 2 )
  • ligne 21 : si la dernière valeur de la pile est plus petite que l'avant dernière valeur de la pile, alors saut en ligne 8
  • ligne 8 : chargement du champ "out" de la classe java.lang.System
  • ligne 11 : chargement de la valeur de la variable 1 ( "Visitez Developpez.com" ) sur la pile
  • ligne 12 : appel de la méthode println de la classe java.io.PrintStream ( le champ out de ligne 8 )
  • ligne 15 : incrémentation de la variable 2 par 1
  • ligne 24 : fin de la méthode

En français, on pourrait dire que la logique de cette méthode est de boucler sur un compteur allant de 0 à 10, et d'appeler à chaque itération la méthode println(String texte) de l'objet System.out.
Pourriez-vous tenter de réécrire cette méthode en Java ?

Code de la classe java
CacherSélectionnez

Aviez-vous trouvé? ;-)

I-C. Décompilateur

Dès que l'on connait les opérations bytecode, ainsi que le langage Java, et que l'on est doté d'une bonne logique, il devient très simple de traduire du bytecode en code source Java.
Et bien c'est exactement ce que fait un décompilateur.

De plus, hormis la logique, d'autres informations sur la classe sont stockées dans le fichier .class : le nom des champs, le nom des méthodes, les exceptions qu'une méthode est susceptible de lancer, etc ...
Grâce à toutes ces informations, le code source peut être restitué exactement !!

Enfin presque. En effet, les commentaires ne sont pas enregistrés lors de la compilation, et sont réellement perdus. Cela dit, le code est parfois plus clair ainsi.
Un seul soucis apparait lors de debug. En effet, du fait de la disparition des commentaires, les points d'arrêts risquent d'être mal placés.

Par exemple si vous mettez un point d'arrêt à la ligne 5 dans un code décompilé, il est tout à fait possible que cette ligne correspondait au départ à une ligne de commentaire, et donc le point d'arrêt ne sera jamais atteint.

Facheux ?

Non, car les informations sur l'emplacement d'une ligne de code sont aussi stockées dans le fichier .class, et donc certains décompilateurs ( dont JAD ) permettent de recréer le fichier source avec la même structure que le fichier original, en remplacant les lignes de commentaires par des lignes blanches.

Il faut cependant avouer que le code restitué n'est plus "totalement" le même avec Java 5 dans le cas particulier des génériques.
En effet, les génériques de Java sont vérifiés durant la phase de compilation ( et généreront une erreur si un type ne correspond pas à celui attendu ), mais sont ensuite traduits en Object. Autrement dit une List<String> sera une simple List dans le bytecode compilé, il devient donc impossible à JAD de rendre la notion de génériques.


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

Ce document est issu de http://www.developpez.com et reste la propriété exclusive de son auteur. La copie, modification et/ou distribution par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.