Reversing e cracking di una applicazione java
(1 lezione)

Data

by "epokh"

�

03/Oct/2004

UIC's Home Page

Published by Quequero

Wong Long il fondatore dello stile Tang Lang disse:

Complimentissimi a epokh, un tutorial di questo tipo ci mancava davvero tanto, grazie tante, spero che il tute serva a incuriosire anche altri reverser.

"Il fine di una tazza è nel suo essere vuota"

....

E-mail: [email protected]

....

Difficolt�

( )NewBies (X)Intermedio ( )Avanzato ( )Master

�
�

Introduzione

Chi pensa che le applicazioni java non siano soggette a cracking si sbaglia di grosso!! Il seguente tutorial è un assaggio sul java reversing e cracking.

Tools usati

Dj java decompiler 3.7
j2sdk

URL o FTP del programma

Crack_me
Cracked_me

Notizie sul programma

Il programma è una applicazione java tipo crack me che per essere registrata richiede un seriale.

Essay

 
Il cracking di applicazioni java stand-alone è un campo vergine non ancora esplorato. Tuttavia la diffusione di questo linguaggio di programmazione multipiattaforma e (quasi) completamente object oriented ha attirato l'attenzione di molti cracker con esperienze in ambito Win32.
 

I cracker suddetti però si sono trovati spiazzati non poco dalla nuova piattaforma sw della SUN che richiede un approccio radicalmente differente da quello delle applicazioni Win32, in quanto fare il debugging di un'applicazione java con il softice significa fare il debugging dell'interprete java e vi assicuro che non è una delle cose più divertenti al mondo?Perchè? .. L'interprete java (lo trovate in /bin/java.exe della vostra JRE) legge gli opcode del byte code dal file .class di cui sta effettuando il parsing, li traduce e a seconda dell'istruzione esegue interrupt (hw e sw),chiamate di sistema, operzioni aritmetiche ecc.

Attenzione: il debugging è difficile ma non impossibile, se ci saranno richieste a sufficienza si potrà approfondire l'argomento.

Comunque in questo tutorial effettueremo il reversing del crack me e non il debugging perciò state tranquilli. La conoscenza di Java è fondamentale, ma basterà conoscere a sufficienza i package java.awt ( platform undependent)e javax.swing (platform dependent).

Passiamo ora al crackme: l'applicazione è distribuita in formato jar, crack_me.jar , lanciamo il programma ( con java -jar crack_me.jar se non avete impostato l'interprete fra le variabili d'ambiente) e sul menu clickiamo Help->Registrati. E' richiesto il nome dell'utente e il seriale in una dialog box simile quelle di Windows.

Se il seriale non è corretto un messaggio di errore ce lo segnala, quindi ora sappiamo dove andare a cercare nel codice dell'applicazione decompilata.

Il primo passo è estrarre le risorse contenute nel file .jar in una cartella. Dico risorse perchè nel jar oltre ai file .class ed al manifesto ci possono essere immagini, eseguibili e tutto quello che può servire all'applicazione in fase di run-time.

Il contenuto del nostro jar può essere visualizzato con: jar tf crack_me.jar l'output è il seguente:

Per estrarre il contenuto possiamo procedere in due modi: con WinZip o con Dj Decompiler. Lanciamo Dj Decompiler ed apriamo il nostro jar dal dialogo open file, a questo punto possiamo vedere tutto il contenuto dell'archivio che estraiamo in una cartella a nostra scelta.

Bene nel mio caso l'estrazione fallisce il programma sembre avere un bug: Fatal Error in UnzDLL.DLL: abort exception. Fa niente lo estraiamo con il winzip. Le risorse sono divise in due cartelle: nella cartella META-INF troviamo il manifesto nell'altra crack_me troviamo i file .class e una immagine png.

Ricordiamo che le cartelle contenenti i file .class corrispondo ai package quindi le classi contenute in una stessa cartella hanno lo stesso scope.

Perchè tanti file per un applicazione tanto piccola? Ricordiamo che in Java il file deve avere lo stesso nomde della classe, quindi ogni classe corrisponde ad un file.Come troviamo la classe contente il punto d'ingresso per l'applicazione? Apriamo il manifesto con il notepad e leggiamo:

M anifest-Version: 1.0
Main-Class: crack_me.Applicazione
Quindi il file nella cartella crack_me, Applicazione.class contiene il metodo main. Decompiliamo con DJ e otteniamo

 
package crack_me;

import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.UIManager;

// Referenced classes of package crack_me:
// Main

public class Applicazione
{

public Applicazione()
{
packFrame = false;
Main frame = new Main(); //costruisce un oggetto di tipo main
if(packFrame)
frame.pack();
else
frame.validate();
.... codice ......
}

public static void main(String args[])
{
try
{ //imposta l'aspetto della gui (SWING) come quello predefinito del sistema
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(Exception e)
{
e.printStackTrace();
}//costruisce se stesso
new Applicazione();
}

boolean packFrame;
}

 
 
 
 
Come possiamo vedere questa classe in sostanza fa due cose: configura il tema della GUI swing e istanzia un oggetto di tipo Main.
Il DJ ci segnala (in celeste) quali classi del package crack_me la classe corrente utilizza cioè Main.class .
Decompiliamo allora anche Main.class :
 
 
// Decompiler options: packimports(3)
// Source File Name: Main.java

package crack_me;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.WindowEvent;
import javax.swing.*;

// Referenced classes of package crack_me:
// Main_jMenuFileExit_ActionAdapter, Main_jMenuHelpAbout_ActionAdapter, Main_jMenuRegister_actionAdapter, Main_AboutBox,
// Register

public class Main extends JFrame
{

public Main()
{

//crezione degli oggetti della GUI
jMenuBar1 = new JMenuBar(); //la barra del menu
jMenuFile = new JMenu();
jMenuFileExit = new JMenuItem();
jMenuHelp = new JMenu();
jMenuHelpAbout = new JMenuItem();
borderLayout1 = new BorderLayout();
jMenuRegister = new JMenuItem(); //ecco la voce per registrarsi
MainInfo = new JTextArea();
enableEvents(64L);
...
jbInit();
}
....

private void jbInit()
throws Exception
{
contentPane = (JPanel)getContentPane();
contentPane.setLayout(borderLayout1);
setSize(new Dimension(400, 300));
setTitle("Un applicazione");
....
jMenuHelp.setText("Help");
jMenuHelpAbout.setText("About");
jMenuHelpAbout.addActionListener(new Main_jMenuHelpAbout_ActionAdapter(this));
jMenuRegister.setText("Registrati"); //questa è l'oggetto menu che ci interessa
jMenuRegister.addActionListener(new Main_jMenuRegister_actionAdapter(this));
//questo è il suo gestore degli eventi
.....
MainInfo.setText("Anche le applicazioni Java si possono reversare!");
....
setJMenuBar(jMenuBar1);
}

....

public void jMenuHelpAbout_actionPerformed(ActionEvent e)
{
......
}

//qui viene gestito l'evento di click sulla voce Registrati

void jMenuRegister_actionPerformed(ActionEvent e)
{
Register dlg = new Register(this);
Dimension dlgSize = dlg.getPreferredSize();
Dimension frmSize = getSize();
Point loc = getLocation();
dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x, (frmSize.height - dlgSize.height) / 2 + loc.y);
dlg.setModal(true);
dlg.pack();
dlg.show();
}

//PUBLIC oggetti della GUI

JPanel contentPane;
JMenuBar jMenuBar1;
JMenu jMenuFile;
JMenuItem jMenuFileExit;
JMenu jMenuHelp;
JMenuItem jMenuHelpAbout;
BorderLayout borderLayout1;
JMenuItem jMenuRegister;
JTextArea MainInfo;
}

Questa volta ci siamo la classe Main infatti eredita da JFrame che è la classe modellante una finestra di Windows, simile ad una WindowClass.
La sezione public della classe contiene gli oggetti della GUI (quelli che interessano a noi):
 
 
1. JMenuBar ->la barra del menu
 
2 JMenuHelp -> il sotto menu di help
 
3 JMenuRegister ->la voce del sottomenu di Help
Il costruttore di Main:
 
1.instanzia gli oggetti della GUI
 
2.chiama il metodo privato jbInit()
Il metodo jbInit() di Main():
 
1.imposta le proprietà degli oggetti della GUI ->jMenuRegister.setText("Registrati");
2.registra gli ActionListener per gli oggetti necessari -> jMenuRegister.addActionListener(new Main_jMenuRegister_actionAdapter(this));

Ma dove sono gli oggetti che gestiscono gli eventi, cioè gli oggetti che implementano l'interfaccia ActionListener? Per l'oggetto jMenuRegister la classe che implementa l'action listener è Main_jMenuRegister_actionAdapter che il DJ ci segnala fra le classi referenziate.

Il metodo che gestisce l'evento di click sulla voce Register è come evidenziato

void jMenuRegister_actionPerformed(ActionEvent e)
{
Register dlg = new Register(this);
.....

dlg.show();

}

Il metodo non fa altro che generare una DialogBox corrispodente all'oggetto dlg di tipo Register. Il metodo dlg.show() serve per visualizzare la DialogBox.

La classe Register è presente nel package locale quindi la decompiliamo:


// Decompiler options: packimports(3)
// Source File Name: Register.java

package crack_me;

import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;

// Referenced classes of package crack_me:
// Main, Register_BottoneReg_actionAdapter

public class Register extends JDialog
{

public Register(Frame parent)
{
super(parent);
......
main = (Main)parent;
.....
jbInit();
....

private void jbInit()
throws Exception
{
.....
....
LabelNome.setText("Utente");
....
TextUtente.setText("");
...
LabelSeriale.setText("Seriale");
...
BottoneReg.setText("Registra");
....
setModal(true);
setTitle("Please Register");
....
}

void BottoneReg_actionPerformed(ActionEvent e) // il gestore dell'evento associato al bottone
{
//qui c'è la routine di controllo del seriale analizzata in seguito

......
if(check)
{
JOptionPane.showMessageDialog(null, "OK", "Applicazione registrata", 1); //messaggio di successo
main.MainInfo.setText("Applicazione registrata");
main.jMenuRegister.disable();
} else
{
JOptionPane.showMessageDialog(null, "No", "Il seriale non \350 corretto", 0); //messaggio di insuccesso
}
dispose();
}

JPanel panel1;
JLabel LabelNome;
JTextField TextUtente;
FlowLayout flowLayout1;
JLabel LabelSeriale;
JTextField TextSeriale;
JButton BottoneReg;
Main main;
}

 

La classe Register eredita da JDialog la classe che appunto modella un dialogo, infatti nella sezione pubblica della classe possiamo notare i componenti del dialogo:

LabelNome ->una label: quella del nome

TextUtente-> il campo per inserire il nome dell'utente

LabelSeriale-> una label: quella del seriale

TextSeriale ->il campo per inserire il seriale

BottoneReg -> un bottone per registrare il seriale

Il metodo che gestisce l'evento associato al bottone è: void BottoneReg_actionPerformed(ActionEvent e) che contiene finalmente la routine di controllo del seriale. Analizziamola:

String user = TextUtente.getText(); -> la stringa user contiene ora il nome dell'utente
String serial = TextSeriale.getText(); -> la stringa seriale contiene ora il seriale inserito
int user_len = user.length(); -> user_len è la lunghezza della stringa utente
int serial_len = serial.length(); -> serial_len è la lunghezza del seriale
boolean check = false; -> sarà l'esito del controllo?
int sum = 0; -> un intero chiamato somma
if(user_len == serial_len) -> 1' controllo : lunghezza di utente e seriale coincidono?
{
if(user_len >= 8 && user_len <= 16) ->2' controllo: lunghezza di utente compresa tra 8 e 16?
{
byte bserial[] = serial.getBytes(); -> converte il seriale in un array di byte (come dato primitivo e non di classe)
int bintserial[] = new int[bserial.length]; -> una array di interi della stessa dimensione del seriale
for(int i = 0; i < bserial.length; i++) -> scorre tutto l'array di byte
{
Byte temp = new Byte(bserial[i]); -> converte un byte (primitivo) in un Byte (di classe)
bintserial[i] = temp.intValue(); -> inserisce nell'array di interi il corrispondete valore intero del Byte
}

for(int i = 0; i < bintserial.length; i++)
sum += bintserial[i]; -> sum contiene la somma dei valori dell'array di interi

if(sum >= 416 && sum <= 420) -> la somma è compresa tra 416 e 20?
check = true; -> se si controllo passato
else
check = false;
}
} else
{
check = false;
}

Riassumendo il controllo del seriale viene fatto in questo modo
1. la lunghezza in caratteri dell'utente è uguale al seriale? Se si prosegui altrimenti seriale non corretto.
2.la lunghezza del seriale o dell'utente è compresa tra 8 e 16? Se si prosegui altrimenti seriale non corretto.
3.converti il seriale in un array di byte e poi in un array di interi che rappresenta il codice dei byte:
Esempio: A -> 0x41 (byte) -> 65 (int)
4.esegui la somma di tutti gli elementi dell'array di interi. Controlla se è compresa tra 416 e 420.
Se si seriale corretto se no seriale non corretto.
Un seriale corretto è per esempio:
Utente: Masssimo (10 caratteri)
Seriale: 28021982 (10 caratteri)
 
 
2 -> 0x32 -> 50 :::: sum=50;
 
 
8->0x38 -> 56 :::: sum=50+56=106
0 -> 0x30 -> 48 :::::sum=106+48=154
2 ->0x32 -> 50 ::::sum= 50+154= 204
1 ->0x31 -> 49 :::: sum=204+49=253
9->0x39 -> 57 :::: sum=57+253= 310
8->0x38 -> 56 :::: sum=56+310= 366
2->0x32 ->50 :::: sum= 50+366= 416

Un vantaggio del reversing in ambiente Java è che il bytecode generato dal compilatore essendo predisposto per un unico processore virtuale è fedele nella maggioranza dei casi al sorgente originale. Quindi possiamo anche: modificare la routine di controllo della classe Register, compilarla e reinserirla nel jar senza aver modificato le altre classi.

Quello che facciamo adesso è impenasabile nel mondo win32:

1.modidichiamo il codice sorgente di Register.java modo che il check sia sempre vero:

if(check=true){.... OK...} else
{..... NO}

2.salviamo il sorgente modificato in un cartella con lo stesso package delle classi, nel mio caso G:\crack_me. Nella stessa cartella copiamo il jar originale crack_me.jar

3.ricompiliamo solo la classe Register usando le classi che stanno nel package, nella cartella crack_me creata :

G:\crack_me\> javac -classpath crack_me.jar Register.java

4.aggiungiamo la classe Register ricompilata nel jar dalla directory superiore, questo è importante altrimenti la classe non verrà aggiunta nel package corretto:

G:\>jar uf crack_me/crack_me.jar crack_me/Register.class

5.verifica

G:\crack_me\>javac -jar crack_me.jar

Incredibile funziona! Mi sono meravigliato anche io la prima volta, ma non bisogna stupirsi più di tanto perchè il Java non effettua un vero e proprio linking dei file .class.

 

������������������������� ������������������������������������������������������������������������������� ...::: EPOKH :::...

Note finali

Spero di trovare altre occasioni per approfondire il cracking in Java. Chiedi e ti sarà dato.

Disclaimer

Vorrei ricordare che il software va comprato e� non rubato, dovete registrare il vostro prodotto dopo il periodo di valutazione. Non mi ritengo responsabile per eventuali danni causati al vostro computer determinati dall'uso improprio di questo tutorial. Questo documento � stato scritto per invogliare il consumatore a registrare legalmente i propri programmi, e non a fargli fare uso dei tantissimi file crack presenti in rete, infatti tale documento aiuta a comprendere lo sforzo che ogni sviluppatore ha dovuto portare avanti per fornire ai rispettivi consumatori i migliori prodotti possibili.

Reversiamo al solo scopo informativo e per migliorare la nostra conoscenza del linguaggio Assembly.�