Newsgroup: it.comp.java
Titolo: Programma che modifica se stesso

ciao a tutti,
avete idea di come fare un programma che modifichi una parte di se stesso?
per esempio, e' possibile che un programma modifichi parte del suo stesso 
codice e poi si salvi modificato?
-- 
ciao
Vittorix 

 ha  
scritto:

I casi son due:
o lavori a livello di scripting grazie le funzionalità introdotte nella  
6.0 (mi pare) o devi portarti dietro i sorgenti che modifichi secondo  
necessità e poi ricompili tramite apposita api
-- 
Manny Calavera
Mail To: anforagimailpuntocom²
Uccidete i filosofi, tenetevi riso e bacchette per voi

 necessità e poi ricompili tramite apposita api
Aggiungerei che, se lavori sotto Windows, mi sembra improbabile che un 
file in esecuzione riesca a salvare... se stesso.

Marco ha scritto:

Modificheresti il codice sorgente, non il file binario.
Guarda un po qui...
http://www.tgofbs.it/?p=68

 necessità e poi ricompili tramite apposita api
no, vorrei distribuire solo il binario, magari offuscato
-- 
ciao
Vittorix 


e' infatti uno dei miei principali dubbi sulla fattibilita'.
 il programma dovrebbe modificarsi mentre e' in esecuzione, mi sa che senza 
i sorgenti e il chiudi/riapri non si fa.
-- 
ciao
Vittorix 

 
http://www.tgofbs.it/?p=68
interessante. mi da' un errore, non trova import 
javax.tools.JavaCompilerTool;
-- 
ciao
Vittorix 


Forse dovresti verificare se, il requisito per cui il programma debba
automodificarsi a livello di sorgente, non possa essere affrontato con
qualche pattern di design ben noto che ti eviti questa soluzione
esoterica.
Inoltre, un programma automodificante potrebbe avere qualche noia con
gli antivirus...

 i sorgenti e il chiudi/riapri non si fa.
nell'era windows200/xp non saprei se e' ancora di moda/fattibile ma
sicuramente sono esistiti virus cosiddetti stealth che si automodificavano
una volta in esecuzione per aggirare gli antivirus. ricordo di averne pure
debuggato uno a suo tempo, giusto per vedere che faceva, e rimasi
piacevolmente sorpreso dalla tecnica che ancora non conoscevo.


mmh, questo è proprio il comportamento dei virus...
--------------------------------
Inviato via 
http://arianna.libero.it/usenet/

 piacevolmente sorpreso dalla tecnica che ancora non conoscevo.
OT: veramente si chiamano virus polimorfici e sono tutt'oggi possibili.
modificano se stessi allo scopo di creare una loro copia che possa essere
associata dall'antivirus ad una signature diversa, possibilmente assente
dal database, in modo da non essere identificati come virus. non entro in
dettagli tecnici perché non è il NG adatto, ma non ci vuole molto, ci può
riuscire anche un quasi-principiante che sappia programmare discretamente
in C e che si sia un minimo documentato.
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 cio' vuol dire che non sarebbe retrocompatibile
non ne ho la più pallida idea, direi di no.
In ogni caso sarebbe javax.script però se vuoi una roba offuscata stai  
andando nella direzione sbagliata


 no, vorrei distribuire solo il binario, magari offuscato
La maggior parte di quelli che sentono questo problema risolvono, oltre che
con l'offuscamento del codice, associando al funzionamento del programma
una chiave, conservata da qualche parte, che contiene una qualche forma di
hash di dati relativi al cliente(che so, il nome, la data di attivazione,
di scadenza del programma). Ovviamente tu solo sai come generare la chiave
e come operare la verifica.
Ciao

 mmh, questo è proprio il comportamento dei virus...
un virus in Java? ne dubito...


> mmh, questo è proprio il comportamento dei virus...
m> un virus in Java? ne dubito...
Non è impossibile un virus in bytecode.
-- 
 /\           ___
/___/\_|_|\_|__|___Gian Uberto Lauri_____
  //--\| | \|  |   Integralista GNUslamico
\/                 e coltivatore diretto di Software
A Cesare avrei detto di scrivermi a	 | To Caesar I woul have said "emai me to
fn...@rat.vg
  (Lui cifrava in rot13) | 
fn...@rat.vg
  (He encrypted wit Rot13)

 codice e poi si salvi modificato?
Sicuramente si. E' quello che avviene regolarmente con le JSP, ad
esempio.
Certo, se tu intendi che una *classe* (quindi non un programma in
senso lato) che modifica il suo .class e poi si autoricarica, beh, la
vedo dura. Ma facendo gestire ad un manager perchè no. D'altra parte è
cosa normale fare compilazione e  deploy delle classi a caldo.

la butto li...
credo che se ti fai un controller che lanci la vera applicazione in un
thread separato riesci in qualche modo a killare il thread, modificare
il sorgente dell'applicazione in qualche modo, ricompilarla e
rilanciare il thread ...
marsel


Vittorix (26/06/2007 20.01.50):

http://jakarta.apache.org/bcel/
Lo sto usando da un paio di mesi e mi sta dando non poche
soddisfazioni. Il mio scenario è questo: a partire dal riferimento ad 
un'interfaccia (ottenuta tramite reflection, quindi un oggetto Class)
avevo bisogno di sintetizzare di volta in volta un'implementazione
concreta di questa interfaccia: la classe risultante doveva essere poco
più di uno "stub" per rilanciare la chiamata prima verso un logger, e
poi verso il vero destinatario della chiamata (che a sua volta
implementava l'interfaccia di cui sopra). Non avendo alcuna intenzione
di costringere i miei utenti ad installarsi tutto il compilatore, in
qualche modo dovevo assemblare il bytecode dello stub per trasformarlo
(tramite una specializzazione di ClassLoader) in una vera e propria
classe, da allocare con newInstance... questa libreria serve proprio
allo scopo!
In pratica ti consente di generare bytecode al volo in memoria
"assemblando" pezzo per pezzo la classe che ti serve, senza necessità
di un compilatore. Dalla documentazione potrebbe sembrarti una cosa
ostica, visto che dovrai lavorare *molto* vicino ai singoli opCode.
All'interno della libreria è presente però un programma che ti viene in
aiuto in questo senso: a partire dal nome di una classe (già
compilata), è in grado di generare del codice sorgente di esempio che,
se eseguito, ricrea il bytecode della classe stessa... non lo proprio
identico al bytecode originale (magari mancante di qualche
ottimizzazione), ma che viene visto dalla JVM come la stessa classe di
partenza. Questo codice sorgente può essere modificato per tutte le tue
esigenze.
Nel tuo caso, con questa libreria dovresti essere in grado di creare al
volo il bytecode delle classi all'interno del tuo programma già in
esecuzione, senza dovrerti appoggiare ad un compilatore, per poi
convertirle in classi al momento di eseguirle.
Spero possa esserti d'aiuto...
-- 
Scientology: se la conosci la eviti, se la conosci non ti uccide...
http://xenu.com-it.net
 - 
http://xenu.freewinds.cx
 - 
http://www.xenu.net
(per rispondere personalmente leva IlDitoDalCulo)
---> 09 F9 11 02 9D 74 E3 5B D8 41 56 C5 63 56 88 C0 <---

 file in esecuzione riesca a salvare... se stesso.
e perchè mai?
intanto parliamo di classi e non di "file".
quando una classe è stata caricata dal classloader mica ci sono problemi 
a scrivere nel .class da cui proviene. il problema semmai è far si che 
l'istanza della classe si "autoricarichi" per rendere effettive le 
modifiche a caldo. basta però vedere il deployer di un qualsiasi 
application server per capire che la cosa in se è fattibilissima.

 piacevolmente sorpreso dalla tecnica che ancora non conoscevo.
tecnicamente è ancora fattibilissimo perchè il sistema non impedisce al 
programma stesso di scrivere nella propria area di memoria riservata al 
codice e quindi modificare il proprio comportamento al volo (spesso 
anche accidentalmente... vedi gli exploit e i buffer overflow).
il problema è che non ha senso. un tempo aveva senso perchè l'antivirus 
andava a fare la mappa della memoria alla ricerca di tsr per pattern, 
ora non lo può fare perchè nella memoria dei processi (virali e non) non 
c'entri.

 Non č impossibile un virus in bytecode.
č possibilissimo che del bytecode faccia danni o invii informazioni
riservate ad insaputa dell'utente, ma il difficile č trovare una
situazione in cui tale software possa nascondersi e rendersi interminabile
come fa di solito un virus. inoltre in genere i virus informatici
"infettano" altri eseguibili nativi della piattaforma in maniera tale che
la loro esecuzione comporti anche l'esecuzione di codice virale, ma per un
virus scritto in Java questo sarebbe molto difficile, proprio perché le
immagini infettate sono native: il virus dovrebbe mettersi a scrivere
codice assembly nativo, e allora tanto vale programmarlo in C cosě scrivi
direttamente il contenuto del tuo stesso codice, con tutte le dovute
accortezze.


 gli antivirus...
altro motivo per cui l'ho scartato
-- 
ciao
Vittorix 

 andando nella direzione sbagliata
infatti, ho semplificato e poi offusco con ProGuard
-- 
ciao
Vittorix 

 mmh, questo è proprio il comportamento dei virus...
infatti poi ci ho pensato e ci ho levato mano.
gia' allarmerebbe un ZoneAlarm e mi pare complicato.
-- 
ciao
Vittorix 

 Ma facendo gestire ad un manager perchè no.
volevo esplorare se ci fosse una soluzione semplice, ma non essendoci ho 
lasciato perdere, cripto un secondo file con AES e offusco il tutto con 
ProGuard
-- 
ciao
Vittorix 

 Spero possa esserti d'aiuto...
interessantissimo. per ora ho deciso di non approfondire oltre, ma potrebbe 
essere utile in futuro
-- 
ciao
Vittorix 

 esoterica.
Non definirei la soluzione 'esoterica'. È abbastanza fuori dal modo di
procedere tipico in Java (proprio perchè scomodo). In Ruby, Python o
Lisp per esempio è del tutto normale 'modificare'  il programma (anche
se spesso non in modo esplicito). 
Direi che è appunto atipica per Java e concordo sul trovare una
soluzione alternativa (o eventualmente cambiare linguaggio, se la
possibilità di modificare il codice evita complicazioni). Ma non la
definirei 'esoterica'.
-- 
blog:  
http://www.akropolix.net/rik0/blogs
 | Uccidete i filosofi,
site:  
http://www.akropolix.net/rik0/
      | tenetevi riso e
forum: 
http://www.akropolix.net/forum/
     | bacchette per voi.

 accortezze.
Questo è un virus in senso stretto. Molti di quelli che vengono
comunemente chiamati 'virus' sono in effetti dei worm che si propagano
in rete. Questi sarebbe possibile scriverli in Java (anche se in effetti
io non lo farei). E comunque ci vorrebbe qualche sistema per fare
partire l'esecuzione dello stesso.


> Non è impossibile un virus in bytecode.
m> è possibilissimo che del bytecode faccia danni o invii informazioni
m> riservate ad insaputa dell'utente, ma il difficile è trovare una
m> situazione in cui tale software possa nascondersi e rendersi
m> interminabile come fa di solito un virus.
Difficile ma  non impossibile.  Ogni  qual volta hai un  interprete (in
hardware o  in software) hai  la possibilità di scrivere  un programma
che  dia in output  se stesso  ed evenutalmente  avviare la  copia. Il
bytecode della JVM non è da meno.
Giustamente fai notare che se  termina la JVM allora termina il virus,
ma ci  sono in giro, e  non sono per  nulla rare, JVM che  sono attive
7/24, e già  si sono visti worm che prendevano  di mira alcune diffuse
applicazioni web (in PHP che sappia io) usando Google per "acquisire i
bersagli".
La diffusione  di un virus è,  tra le altre  cose, strettamente legata
alla  diffusione della  macchina virtuale  (include quelle  create dai
vari S.O.) o no.
La fattibilità e la distruttività di  un virus è legata prima di tutto
a  quanto è  permissivo il  sistema  che ospita  la macchina  virtuale
attaccata: se riesci  a trovare una chiave per  riavviare il tuo virus
senza usare il  "cavallo di troia" iniziale, allora  bingo, il virus è
fattibile. E usualmente puoi fare danni, perché vuole dire che hai una
certa libertà di alterare i dati sullo storage.
Se il sistema  ha protezioni sufficienti ed è  configurato ed usato in
modo opportuno, non hai molte chanche. É il motivo per cui alcuni S.O.
hanno la  fama di essere più  sicuri di altri,  "escono dalla scatola"
con  configurazioni sensate  e c'è  diffusa tra  gli utenti  che "fare
certe cose è male".
Ma se  il sistema non  ha protezioni sufficenti  oppure le ha  ma sono
disattivate,  puoi fare in  modo di  far riavviare  al sistema  il tuo
programma maligno ed è fatta. Anche se è in Java.
Ora,  il fatto  che  Java giri  su  S.O. diversi  già  crea una  prima
potenziale  settorializzazione dei possibili  virus, dato  che sistemi
diversi  possono  avere  modi  diversi  di avviare  in  automatico  il
programma.   
Io penso  che comunque  vada considerato il  perché viene  generato un
virus.
Caso innocuo, qualcuno vuole  fare un programma autoreplicante. Se non
gli scappa (vedi il mitico  Internet Worm - peraltro multi hardware -)
non  farà problemi e  sopratutto non  avrà un  payload di  attacco. La
minaccia è relativamente bassa, che se qualcuno fa un virus con questi
scopi allora fa di tutto per tenerne controllati gli effetti.
Caso dannoso, qualcuno  vuole fare sapere che è un  coder più 733(? si
scrive così ? :)  ) di altri. In questo caso il  virus deve fare danni
(o nessuno ne parla), diffondersi tanto (che idem, nessuno ne parla) e
(opzionale) colpire gli "inferiori".
Una piattaforma che non offre  queste ricompense dubito che diventi un
obiettivo appetibile. Potrei sbagliarmi, ma la mia idea è questa.


> questa soluzione esoterica.
E'OF> Non definirei la soluzione 'esoterica'. È abbastanza fuori dal
E'OF> modo di procedere tipico in Java (proprio perchè scomodo). In
E'OF> Ruby, Python o Lisp per esempio è del tutto normale 'modificare'
E'OF> il programma (anche se spesso non in modo esplicito).
Direi che tutto deriva dalla presenza di una eval(), che in Java appunto
NON hanno messo.


 NON hanno messo.
Per Lisp forse. Per Python e Ruby no, certo c'è la eval (e in questi
tempi io in Python sto precisamente scrivendo un compilatore che mi
permette di valutare espressioni in un semplice linguaggio 'matematico'
e di compilarle in bytecode per la VM Python, poi encapsularle come
funzioni e poterle usare come funzioni 'vere'.
Per Python ho presente anche una libreria di bytecode hacks e tutto. Ma
quello che dicevo io era più facile. In entrambi i linguaggi puoi
rimanendo dentro il rispettivo linguaggio e senza passare per la
valutazione di stringhe modificare vari componenti, aggiungere o
modificare il comportamento delle classi e così via.
La cosa in comune è che per un programmatore Lisp, Python o Ruby è del
tutto normale concepire un programma che a runtime modifica se stesso,
aggiungdo behaviour, modificandola etc etc etc. Per un programmatore
Java invece si è nel campo della magia nera (come lo è per un
programmatore C: in determinati casi è possibile generare per esempio
codice eseguibile -- anche se molto probabilmente le architetture che
hanno una qualche protezione contro lo smashing dello stack impedendo
l'esecuzione di roba fuori da text lo bloccherebbero).
Allo stesso modo codice come:
      try{
        Method m = disp_class.getMethod(method_name);
        m.invoke(d);
      } catch(NoSuchMethodException e){
        System.out.println("Couldn't find method " + method_name + ".");
      } catch(IllegalAccessException e){
        System.out.println("Couldn't invoke method " + method_name +
".");
      } catch(InvocationTargetException e){
        System.out.println("Couldn't invoke method " + method_name +
".");
      }
è legale in Java, anche se usato nei programmi normali molto meno di
quello che viene fatto in Ruby o in Python, dove spessissimo quando c'è
da fare dei dispatch si usa roba del genere.
La reflection in Java, anche se molto inferiore a quella che si ha in
Python come comodità, è abbastanza usabile. Eppure a quanto vedo è usata
meno di quanto potrebbe.


 funzioni e poterle usare come funzioni 'vere'.
Questa del compilatore mi rendo conto che non c'entra una fava con la
eval. La cosa si doveva leggere come:
Certo in Python c'è la eval, ma per ovvie ragioni è pochissimo usata.
Addirittura in questi tempi io...
... 


 writes:
E-OF> try{
E-OF>   Method m = disp_class.getMethod(method_name);
E-OF>   m.invoke(d);
E-OF> } catch(NoSuchMethodException e){
E-OF>   System.out.println("Couldn't find method " + method_name + ".");
E-OF> } catch(IllegalAccessException e){
E-OF>   System.out.println("Couldn't invoke method " + method_name + ".");
E-OF> } catch(InvocationTargetException e){
E-OF>   System.out.println("Couldn't invoke method " + method_name + ".");
E-OF> }
E'OF> č legale in Java, anche se usato nei programmi normali molto meno di
E'OF> quello che viene fatto in Ruby o in Python, dove spessissimo
E'OF> quando c'č da fare dei dispatch si usa roba del genere.
Hmmm...  Devo  ancora decidere se  questa tecnica mi piace.   Ho visto
troppe volte  programmi il cui  funzionamento era affidato  a stringhe
costanti (invece  che ad oggetti del linguaggio)  avere una gestazione
lunga, dolorosa ed insanguinata. Anche se probabilmente c'č il modo di
scriverlo in modo "verificabile dal compilatore".
Il problema  per cui in Java non  ho visto usare molto  i "puntatori a
funzione" (che  quello sono  gli oggetti  Method :) )  mi pare  sia da
cercarsi tra le tastiere e le sedie dei programmatori disponibili.


 cercarsi tra le tastiere e le sedie dei programmatori disponibili.
In effetti sono qualcosa di più: sono 'puntatori a funzione chiamabili
per nome'. In teoria sarebbero anche più comodi dei puntatori a
funzione, da questo punto di vista.
Io mi sono reso comunque che la sintassi di un linguaggio è
determinante: ci sono cose possibili in determinati linguaggi che però
non vengono fatte quasi mai perchè hanno una sintassi macchinosa.
Un esempio è l'estensione di una classe a runtime. In Ruby viene fatto
ogni 3x2, in Python molto di rado. Semanticamente lo fanno entrambi in
modo banale, ma la sintassi di Ruby è più rassicurante a riguardo.


> c'è il modo di scriverlo in modo "verificabile dal compilatore".
E'OF> Io da programmatore dinamico posso dirti che lo faccio e lo ho
E'OF> visto fare spesso, senza sostanzialmente nessun
E'OF> problema. L'unico problema che ho visto è che potenzialmente c'è
E'OF> un inghippo prestazionale (immagino ancora più marcato in
E'OF> Java). Per il resto il codice se scritto cum grano salis è
E'OF> sicuro.
E'OF> Se il metodo non viene trovato viene lanciata precisamente
E'OF> un'eccezione, sia in Java che nei linguaggi dinamici. Nota che
E'OF> nei linguaggi dinamici sarebbe un'eccezione anche se chiamassi
E'OF> un metodo non esistente usando la sintassi tipica invece che
E'OF> l'indirezione.
Ci sono due obiezioni al tuo ragionamento:
La prima è la necessità di Cum Grano Salis. La seconda è indirettamente
legata alla prima.
Gosling, avendo visto  che il management non rispetta  la quota minima
di sale per programmatore (e poi li massacra perché ovviamente i costi
raggiungono  Alpha  Proxima  fregandosene  dei limiti  delle  velocità
relativistiche)  ha  concepito  un  linguaggio che  verifichi  il  più
possibile meccanicamente la coerenza degli oggetti e dei loro usi.
Introdurre queste stringhe butta un po' la cosina alle ortiche.
La mia idea era eventualmente  riuscire a creare un meccanismo tipo le
enums.Enum  di Apache  Common per  cui  il metodo  di dispatching  non
accetti una  banale stringa, ma una  stringa generata in  modo tale da
poter valere solo  i nomi dei metodi. Se ho tempo  provo a studiare la
cosa.


 cosa.
Mi pare una buona idea... sto volentieri in ascolto.


> la cosa.
E'OF> Mi pare una buona idea... sto volentieri in ascolto.
Mi  ero espresso  male,  non si  tratta  di una  stringa come  oggetto
String, ma del nome del  riferimento un oggetto di un tipo particolare
definito in modo da creare una enumerazione di valori possibili. Non ho
tirato in ballo la classe della Apache Foundation per questo giochino.
/**
 * Describe class Disp here.
 *
 *
 * Created: Tue Jul  3 11:23:30 2007
 *
 * @author <a href="mailto:
sa...@spammer.impiccati.it
">Gian Uberto Lauri</a>
 * @version $Revision$
 */
public class Disp {
	/**
	 * Crea una nuova istanza di <code>Disp</code> .
	 *
	 */
	public Disp() {
	}
	public void pippo()
	{
		System.out.println("pippo");
	}
	public void pluto()
	{
		System.out.println("pluto");
	}
	public void paperino()
	{
		System.out.println("paperino");
	}
	public Object dispatch(MethList metodo)
	{
		return metodo.invoca(this);
	}
	/**
	 * <code>main</code>
	 *
	 * @param args a <code>String[]</code>
	 */
	public static final void main(final String[] args) {
		Disp d = new Disp();
 
		d.dispatch(MethList.pippo);
		d.dispatch(MethList.pluto);
		d.dispatch(MethList.paperino);
	}
}
// --- MethList.java
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
/**
 * Questa e` la classe che genera l'enumerazione che puo` valere solo
 * pippo, pluto e paperino. Per chiarezza dell'esempio ho lasciato gli
 * stessi nomi che ci sono in Disp (oppure cosi` facendo ho generato
 * confusione)
 *
 *
 * Created: Tue Jul  3 11:23:50 2007
 *
 * @author <a href="mailto:
sa...@spammer.impiccati.it
">Gian Uberto Lauri</a>
 * @version $Revision$
 */
public class MethList {
	private Method metodo;
	public final static MethList pippo;
	public final static MethList pluto;
	public final static MethList paperino;
	static {
		try {
			pippo = new MethList("pippo");
			pluto = new MethList("pluto");
			paperino = new MethList("paperino");
		} catch (NoSuchMethodException e) {
			throw new InstantiationError("Programmatore mona: " +
										 e.getClass().getName() + " " +
										 e.getMessage());
		}
	}
	/**
	 * Crea una nuova istanza di <code>MethList</code> .
	 *
	 */
	private MethList(String nome) throws NoSuchMethodException {
		metodo = Disp.class.getMethod(nome,new Class[0]);
	}
	public Object invoca(Object questo)
	{
		try {
			return metodo.invoke(questo, new Class[0]);
		} catch (IllegalAccessException e) {
			throw new IllegalAccessError("Programmatore mona: " +
										 e.getClass().getName() + " " +
										 e.getMessage());
		} catch (InvocationTargetException e) {
			// Qui si dovrebbero tirare fuori le eccezioni vere che
			// hanno causato e, per questa prova uso la gestione
			// precedente perche' sono pigro...
			throw new IllegalAccessError("Programmatore mona: " +
										 e.getClass().getName() + " " +
										 e.getMessage());
		}
	}
}
Questo e` il giochino che ho tirato fuori in una mezz'oretta di
divertissment.
Non  ha l'immediatezza  di dover  scrivere una  semplice  stringa ogni
volta che aggiungo un metodo (devi infatti modificare l'enumerazione),
ha il vantaggio che l'oggetto Method lo generi una volta per tutte.
Però,  a pensarci bene,  usualmente un  dispatcher richiama  tutta una
serie  di metodi  simili come  firma,  sopratutto se  deve scoprire  a
runtime il metodo da richiamare.
A questo  punto, invece  che lavorare di  reflection sui metodi  di un
singolo dispatcher, mi sa tanto  che conviene mettere i vari metodi in
varie  classi  che implementano  una  apposita  interfaccia e  casomai
costruire  l'enumerazione  con  istanze  delle  classi  (eventualmente
pooled se ci sono problemi di concorrenza su una medesima istanza).
Hmmm, mi sa che è per questo che non si usa la reflection in Java. Non
serve  realmente, se hai  bisogno di  un oggetto  su cui  chiamare una
funzione passi un istanza  che implementi l'interfaccia che garantisce
la presenza di quella funzione.
E poi,  anche Steele lo  ha detto, con  Java hanno portato  i program-
matori C++ a metà strada verso il LISP...
