Pergunta

Java pode ser "desmontado" e "descompilado"?

Resposta

Após a compilação, tanto as aplicações como as applets estão na forma de bytecodes, isto é, uma espécie de assembly (linguagem de máquina) destinado às máquinas virtuais Java. Como tal especificação é pública (embora de propriedade da Sun MicroSystems), torna-se relativamente fácil obter-se o código que originou uma aplicação ou applet.

O JDK (Java Developer's Kit), fornecido gratuitamente pela Sun) inclui o programa javap, um disassembler Java que pode ser usado para obter-se a estrutura interna e o código em bytecodes relativamente legível.

Tomemos o seguinte programa fonte como exemplo:

// Classe Oi
public class Oi {
  // Método principal
  public static void main(String args[]) {
    // Impressão do Oi
    System.out.println("Oi!");
  }
}

Ao compilá-lo obtemos o arquivo "Oi.class":

javac Oi.java

Poderíamos "desmontar" seu código como segue:

javap Oi.java

Que produziria o seguinte resultado:

Compiled from Oi.java
public synchronized class Oi extends java.lang.Object
    /* ACC_SUPER bit set */
{
    public static void main(java.lang.String[]);
    public Oi();
}

Method void main(java.lang.String[])
   0 getstatic #7 <Field java.io.PrintStream out>
   3 ldc #1 <String "Oi!">
   5 invokevirtual #8 <Method void println(java.lang.String)>
   8 return

Method Oi()
   0 aload_0
   1 invokespecial #6 <Method java.lang.Object()>
   4 return

Embora isto não seja o código fonte original, programadores Java experientes poderiam entender o mesmo se possuirem um cópia da especificação da máquina virtual Java.

Programas tais como o Mocha de HanPeter van Vliet ou o JAD de Pavel Kouznetsov podem ser utilizados para obter-se código Java semelhante ao original.

Utilizando o Mocha obteríamos o seguinte código:

/* Decompiled by Mocha from Oi.class */
/* Originally compiled from Oi.java */

import java.io.PrintStream;

public synchronized class Oi
{
    public static void main(String astring[])
    {
        System.out.println("Oi!");
    }

    public Oi()
    {
    }
}

Utilizando o JAD 1.57 obteríamos o seguinte código:

// Decompiled by Jad v1.5.7. Copyright 1997-99 Pavel Kouznetsov.
// Jad home page: http://www.oocities.org/SiliconValley/Bridge/8617/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   Oi.java

import java.io.PrintStream;

public class Oi
{

    public static void main(String args[])
    {
        System.out.println("Oi!");
    }

    public Oi()
    {
    }
}

Uma rápida verificação mostra que os resultados produzidos pelos decompilers usados são muito semelhantes ao código original. Embora apresentem pequenas diferenças entre si, o código recuperado permite desvendar como uma certa classe foi implementada.

Dada a facilidade com que a decompilação de código Java pode ser realizada, tanto pelo fato do formato bytecode das classes ser conhecido como pela disponibilidade de diversas ferramentas para tal finalidade, existe uma grande preocupação dos desenvolvedores Java na preservação seu código. Para isto podem ser usadas técnicas de ofuscação de código ou programas ofuscadores de código (JavaFaq 0095).