Newsgroup: it.comp.lang.c++
Titolo: decompilare

Ho letto su questo NG che è possibile decompilare un file se ho capito
bene.Sareste cosi gentili da dirmi che cosa occorre?Forse è una strada per
vedere del codice sorgente da cui imparare qualcosa di veramente pratico?
Grazie!

 vedere del codice sorgente da cui imparare qualcosa di veramente pratico?
No, non vedere il codice sorgente ma vedere il codice assembly. Esistono 
  decompilatori che cercano di ricostruire anche il codice, ma il 
risultato è solitamente illeggibile.

vedere del codice sorgente da cui imparare qualcosa di veramente pratico?
Valida quanto partire da un cordon bleu per risalire al pollo iniziale
:-)
L'open source è nato anche per venire incontro ad esigenze come la
tua. C'è gente che si impegna a lasciare il codice dei programmi
disponibile, in modo che altri possano consultarlo. Un sito come
sourceforge.net
 è una miniera di informazioni a proposito. Collegati e
scarica qualche progetto.

 :-)
ROTFL!!!! :-)

 Grazie!
Per me è servito!
Vedere come traduce un compilatore il sorgente in assembler ti aiuta a 
spingerti oltre l'ottimizzazione. Infatti i compilatori di alto livello 
inseriscono molti comandi inutili. Ad esempio:
il seguente codice
long A, B;
C = A-B;
if (A=B)
{
	...
}
non viene tradotto nel seguente modo
mov eax, A
sub eax, B
jnz pippo
	...
pippo:
detto ciò a me è anche servito per cercare di tenere lontano i cracker 
dandogli parecchio filo da torcere!

pippo:
A parte che il codice che riporti è errato (A == B, non A = B), non
capisco qual è l'ottimizzazione a cui ti stai riferendo...

 Immagino tu stia scherzando.
E' ovvio che il compilatore produrrà un po' di codice inutile, ma IMHO è
talmente poco e talmente irrilevante che mettersi ad "ottimizzare" un
programma così è davvero da uscirne pazzi (amenoché non si tratta di
cose *semplici*).
Enrico

E' ovvio che il compilatore produrrà un po' di codice inutile
Guarda che non è affatto così ovvio...

 pippo:
Si ma tu hai la garanzia che questa versione sia sempre il 
codice milgiore e più adatto sulla base dei cicli di clock ?
Poi, capisco che l'esempio era solo didattico, ma nel tuo 
asm non referenzi la variabile C (deve esserci una scrittura 
in memoria su essa, del risultato).
ciao
Soviet


 Guarda che non è affatto così ovvio...
Specialmente con le opzioni di ottimizzazione giuste.
Certo, se prendono l'output bruto è pieno di istruzioni inutili. 
Che sono li perchè uno non ha voluto ottimizzare (per esempio perchè sta
ancora sviluppando). 
-- 
-riko

 non viene tradotto nel seguente modo
Guarda che i compilatori sono più furbi di quanto pensi. Per esempio:
int g(int a, int b)
{
    int c = a - b;
    if (a == b) {
        return a;
    } else {
        return b;
    }
}
diventa:
.globl _g
_g:
        pushl   %ebp
        movl    %esp, %ebp
        movl    12(%ebp), %eax
        leave
        ret
Poi fare i conti con le performance prendendo il merdosissimo asm x86 è
da pazzi fottuti, visto che l'endoarchitettura e l'esoarchitettura dei
moderni processori Intel e Amd non sono parenti nemmeno alla lontana. Ma
vabbè. Si gioca.
Una cosa come:
int g(int a, int b)
{
    int c = a - b;
    if (a == b) {
        return c;
    } else {
        return b;
    }
}
diventa:
.globl _g
_g:
        pushl   %ebp
        movl    %esp, %ebp
        movl    8(%ebp), %edx
        movl    12(%ebp), %ecx
        leave
        movl    %edx, %eax
        subl    %ecx, %eax
        cmpl    %ecx, %edx
        cmovne  %ecx, %eax
        ret
A margine, ti faccio notare che il leave piazzato a metà non c'è finito
per caso, ma per un preciso motivo. Sai perchè?
-- 
-riko

infiniti contesti.
Questo non sta scritto da nessuna parte. Il compilatore puņ prendere
decisioni mirate in base alla piattaforma. Non č un caso che molti
compilatori (vedi gcc) accettino opzioni specifiche per marca e
modello di processore.

 modello di processore.
mi sono spiegato male.
Non ho detto che una stessa scrittura di alto livello debba 
produrre sempre lo stesso binario, ma che una stessa 
scrittura (salvo quando chiesto diversamente, tipo con 
l'overloading o il mecc. virtuale) deve produrre sempre gli 
stessi effetti attesi. Questo naturalmente, in contesti 
differenti, può magari portare a codice binario differente, 
a seconda che varie scorciatoie siano possibili o meno.
Nella sostanza intendevo dire che confrontare un proprio 
assemply svincolato da un contesto con una routine 
sviluppata e contestualizzata, è un non senso in termini, 
perché il primo codice si prende magari dei rischi in più 
che il compilatore non fa.
ciao
Soviet

che il compilatore non fa.
Mi spiace ma hai un linguaggio troppo contorto. Non riesco davvero a
capire quello che scrivi.

 capire quello che scrivi.
Dice che il compilatore (eventualmente) ottimizza in modo diverso su
macchine diverse, ma è obbligato a mantenere la semantica delle
istruzioni.
Viceversa scrivendo a mano, tipicamente si scrive per una classe
ristretta di architetture hw. 
Per cui, di fatto, ha poco senso fare il confronto.
Questo ha scritto: sono sostanzialmente parole di Soviet, non mie! :P
-- 
-riko

istruzioni.
Questo l'ho letto e capito (era il primo pezzo). Quello che non ho
capito è il secondo, ma conoscendo le contorsioni solite di Soviet,
non è un gran problema.
Non mi sembra che il fatto che il compilatore debba mantenere una
semantica uniforme sia una affermazione degna del Nobel. E' insito nel
concetto stesso di correttezza del codice prodotto da un compilatore.
Se un compilatore non mantenesse valida la semantica, avrebbe dei
problemi seri.

 problemi seri.
Però se tizio scrive una routine che usa tutti i registri 
per le variabili locali, magari batte il compilatore a 
performance, ma non può impunemente innestare il suo codice 
in qualsiasi punto di qualsiasi programma senza averlo 
passato al setaccio garantendo pari trasportabilità e 
solidità, pena i crash in agguato.
Allora, ribadisco, è un confronto dove il compilatore deve 
correre zavorrato contro uno che sgambetta libero e senza 
vincoli, ergo batterlo o meno significa poco.
Per inciso penso che si possano battere solo in rari punti 
molto circoscritti, e pagando prezzi di tipo diverso dalla 
velocità pura (se ne valga la pena e dove, lo giudichi 
ciascuno. Io quella fissazione l'ho persa dieci anni fa 
almeno, ma allora i calcoli floating point emulati sw erano 
piuttosto lenti rispetto al coprocessore matematico. Oggi è 
non è molto attuale tale argomento)
ciao
Soviet

performance,
Se ci sono delle condizioni per cui tu puoi pensare a certi tipi di
ottimizzazione, stai tranquillo che ci arriva anche il compilatore.

Enrico Franchi ha scritto:

Però non pensavo di scatenare un mega questione.. Ho solo detto che la 
mia esperienza di analisi mi ha aiutato a vedere alcune cose in modo 
differente! Non volevo mica dire che bisogna scrivere tutto in codice 
ASM anche se io ho gia scritto più di qualcosina: non perchè son pazzo o 
chissà cosa, ma perchè non c'era altro modo di scriverla. Avevo bisogno 
di software veramente performante e soprattutto "astuto". Poi chi vuol 
capire capisce altrimenti non mi di dilungo in altre spiegazioni.
PS: è vero la sintassi corretta era if (A == B): orrore il mio di 
digitazione, perdonate.
PSS: Guarda che anche l'opcode da voi scritto può essere tradotto in 
modo differente in base al compilatore che utilizzate, addirittura il 
processore stesso può eseguirlo in modo diverso! Quindi il mio moto è 
capire come funziona sotto per scrivere un grande codice sopra.

capire come funziona sotto per scrivere un grande codice sopra.
Il grande codice sopra dipende generalmente dall'ottimizzazione degli
algoritmi, non da come quegli algoritmi vengono tradotti.

Andrea Laforgia ha scritto:

Credo di aver capito cosa intende Soviet: l'utente potrebbe scrivere 
funzioni che non rispettino le convenzioni di chiamata (mi pare si 
chiami ABI). In effetti credo che anche il compilatore potrebbe 
ottimizzare le funzioni con linking statico, per le quali ha completa 
conoscenza di come verrà chiamata. Ma dubito che questo tipo di 
ottimizzazioni vengano fatte.
E.

 per caso, ma per un preciso motivo. Sai perchč?
LEAVE č sinonimo di MOV SP, BP/POP BP, quindi elimina lo stack
frame della subroutine... e sta lě perchč gli argomenti sono
giŕ stati tutti caricati nei registri: i calcoli fra registri
non interessano la memoria e la LEAVE viene cosě eseguita in
parallelo alle operazioni aritmetiche.
Ho vinto qualcheccosa?? ^_^

 Ho vinto qualcheccosa?? ^_^
:P
-- 
-riko

 capire come funziona sotto per scrivere un grande codice sopra.
Da "voi" chi? Io ho scritto un sorgente C e il compilatore lo ha
tradotto in quel modo. Grazie per avermi ricordo che cambiando
compilatore il codice generato cambia, non ci sarei arrivato senza il
tuo intervento (ma poi non capisco cosa c'entra). Se siamo in vena di
cose ovvie, anche cambiando le opzioni di compilazione il codice cambia.
Ora dirò qualcosa di nuovo: se poi cambiamo il target, anche in quel
caso il codice cambia! :P
Il fatto che il processore esegua in modo diverso un codice è un'altra
cosa piuttosto ovvia, visto che l'endoarchitettura dei processori è
piuttosto diversa a seconda del modello. Specie nel mondo x86. 
La differenza è che in generale i compilatori hanno una buona conoscenza
del funzionamento del processore e di fatto esistono precise opzioni per
dire loro quale deve essere il target per cui ottimizzare. Che è invece
quello che i programmatori a mano non possono fare: gestire i vari
modelli renderebbe il tutto infattibile.
Questo non vuole dire che *mai* si possa usare asm. Semplicemente i casi
di utilizzo sensati sono notevolmente più rari di quello che il profano
pensa. Ma non vedo dove porti questo discordo.
-- 
-riko

Complimenti a tutti per le nozioni avanzate che avete! Sembra che negli 
ultimi anni non avete fatto altro che debuggare e decompilare software! 
Quindi non capisco dove sia il problema! Se ho risposto di si alla domanda:
"Ho letto su questo NG che è possibile decompilare un file se ho capito
bene.Sareste cosi gentili da dirmi che cosa occorre? Forse è una strada 
per vedere del codice sorgente da cui imparare qualcosa di veramente 
pratico?
Grazie!"
A me è servito!
Avete ragione se scrivete che un grande codice si scrive con un grande 
algoritmo! Ma un grande algoritmo scritto molto bene è più performate 
dello stesso scritto male.. o mi sbaglio! (Escludendo da questa 
affermazione la VARIABILE TEMPO A DISPOSIZIONE :-) e COMMISSIONARIO 
IMPAZZIENTE)!
Per "ASTUTO" mi riferivo a qualche trucchetto che uso: come scrivere 
codice automodificante o semplicemente illudere il decompilatore ed i 
debuggers, passare in modalità reale bloccando tutti gli interrupt senza 
far capire che lo stai facendo, modificare la struttura interna di un 
file EXE e farlo comunque eseguire.. Insomma penso ne sappiate molte e 
molte più di me! o sbaglio!
Poi penso che leggere libri sul funzionamento di un sistema operativo, 
non aiuti mai come far il reverse engineering dello stesso. 
Semplicemente perchè lo vivi! Scusate il pensiero quasi poetico ma 
quando ho analizzato per la prima volta il KERNEL del allora Win2k/NT 
4.0 vivevo una specie di simbiosi ogni cosa che capivo e scoprivo mi 
avvicinava sempre più alla logica di chi l'aveva progettata e sempre più 
  alla logica dell'architettura i386.
Per quanto riguarda
Da "voi" chi? Io ho scritto un sorgente C e il compilatore lo ha
tradotto in quel modo. Grazie per avermi ricordo che cambiando
compilatore il codice generato cambia, non ci sarei arrivato senza il
tuo intervento (ma poi non capisco cosa c'entra).
Non mi riferivo a compilatori C ma a compilatori ASM e lo detto come 
autocritica, ossia: Il codice ASM non solo è più complicato da gestire, 
  ma spesso viene tradotto in comandi esadecimali non è fedeli, perciò 
non vale la pena perderci molto tempo sopra per qualche unità di clock! 
che però non deve trasformarsi in qualche milione di clock! Altrimenti 
la clessidra del mouse le fa girare all'utente che lo utilizza! E per 
fottersi qualche milione di clock è un attimo:
Immaginate se il processore facesse solo le operazioni che 
necessitano... (Dual Processor 2.6 GHz sono oltre 4.000.000.000 di 
operazioni al secondo, che per 1 minuto di loading del O.S. diventano 
oltre 240.000.000.000 di operazioni al secondo.. un po' esagerato non 
trovate?) Non parliamo della RAM e delle dimensioni di un eseguibile..
Comunque il mondo non si cambia e questa è la sua direzione lo sappiamo 
tutti! :-(

 trovate?)
Beh, questo conto non ha molto senso. La gran parte del tempo il 
processore lo passa aspettando che arrivino i dati dalla memoria o dalla 
rete o dall'hard-disk...
Comunque anch'io sono dell'idea che molti programmi sono troppo pesanti. 
  Appena hai un hardware un po' vecchiotto è più il tempo che l'utente 
passa ad aspettare il computer che non viceversa.
E.

 
CUT ALL
Ciao
Soviet_Mario



Se non mi sbaglio quella volta sono entrato in modalità kernel e qui sai 
già che ci sono varie possibilità per arrivarci.. pensate da microsoft o 
meno :-)
Ho aumento la priorità di un interrupt hardware (ad es.: irq0 Visto che è 
quello che viene più chiamato: MSDN di WinNT|2k|XP dice che è regolato ad 
una frequenza bassa in realtà non è così) in modo tale che per un bel pò 
gli altri non rompano.
Ho inserito una bella isr con la quale sono andato a configurare l'APIC 
ed il multitasking in modo tale che nessun altra cosa blocchi il mio 
codice, son passato a modalità reale, eseguito ciò che volevo... rimesso 
tutto in ordine.
Più tosto se metti qualche jmp e a ritroso nella irq3 giusto per eseguire 
un po' di opcode automodificante che cambia alla fine ciò che il debugger 
pensa di aver intercettato.. Ma questo è un altro discorso..
Spero di non aver dimenticato nulla.
 

 tutti! :-(
Mi sembra un nonsense. In primo luogo il conto che stai facendo ha senso
se consideri il throughput (o se preferisci il numero di operazioni
*completate* in un secondo). Stai anche bellamente ignorando tutte le
condizioni che costringono a uno svuotamento della pipeline, etc etc
etc. Per non parlare del fatto che non tieni in considerazione le
gerarchie di memoria (e in particolare non conti gli accessi in RAM e
peggio ancora non conti quelli su disco). Insomma, sono numeri
abbastanza a caso i tuoi.
-- 
-riko

 abbastanza a caso i tuoi.
Quello che volevo dire è che la maggior parte dei "PROGRAMMATORI" non 
conosce il codice ASM, e scrive alla super capsula, tradotto: "Ma che 
cosa ha questo PC! E' impiantato! Hai un Virus, no è Spyware, no no è un 
Malware, prova a togliere qualche processo, cambia i registri..." 
L'utente finale, "che ne sà molto più di noi", hai presente come si 
diverte con i consigli degli amici. E da qui l'oblio.

 diverte con i consigli degli amici. E da qui l'oblio.
Uh? In primo luogo, quale è il problema di un programmatore che non
conosce l'assembly? Posto che sapere una cosa è meglio che non saperla,
ci sono una dozzina di cose più vitali che sapere l'asm al giorno
d'oggi. Per esempio sapere qualcosa di ingegneria del software.
Conoscere delle buone metodologie di sviluppo, conoscere bene i
protocolli e le tecnologie che si usano. 
Lo sviluppo si sposta sempre più verso linguaggi di alto livello (o con
features di alto livello). Ci sono un numero elevatissimo di buoni
motivi per farlo, fra cui il fatto che semplicemente i colli di
bottiglia per moltissime applicazioni *non* sono la computazione.
Detto tutto questo, non vedo la correlazione fra "programmatori",
"conoscere il codice ASM" (e poi questo che vuole dire... ci sono un
fottio di architetture hardware diversi con il loro asm, per non parlare
di quelli delle macchine virtuali), "virus" e "spyware".
Il programmatore non è quello che ti mette a posto il computer, tanto
per dire. 
-- 
-riko

 diverte con i consigli degli amici. E da qui l'oblio.
Chiacchiere prive di senso.

 per dire. 
So benissimo che sono due cose diverse, ma se scarichi un programma 
freeware trovato in rete, sei sicuro di avere la garanzia che non sia 
stato scritto dal tecnico della domenica "smanettone di VB"?

 stato scritto dal tecnico della domenica "smanettone di VB"?
Continui a porre frasi di pseudo-effetto in conclusione. 
Comunque io la garanzia la ho: sulle mie macchine non gira Windows e di
conseguenza non girano nemmeno programmi scritti in VisualBasic. Quando
uso Windows se il programma è scritto in VisualBasic da qualcuno che sa
come programmare per me va benissimo.
Se è scritto in quello che vuoi da un praticone che non conosce le
pratiche tipiche della buona programmazione, non sa come organizzare
codice mantenibile, usare test-suite per contenere il numero dei bachi e
non sa come realizzare una buona interfaccia utente... ecco, in questo
caso è molto più probabile che lo cestini. Anzi, è praticamente certo.
-- 
-riko

Ok! Abbandono mi rendo conto che la mia esperienza è quasi totalmente 
riferita al controllo di periferiche in Realtime legate molto al HW, 
algoritmi di compressione (da me pensati e creati) e da software che 
protegge altro software. Tutto il resto è quasi buio, quindi ho solo da 
imparare!
Mi rendo conto che vi sta molto a cuore il linguaggio "ALTO", ma dal mio 
"BASSO" riesco ancora a sorprendere, se non altro per le idee!

Alessandro Marini ha scritto:

Il linguaggio "alto" non c'entra nulla : come tutto, dipende sempre dal 
contesto :-)
[Step motor comandati in PWM ??? Non sara' stato invece un motore 
brushless??? ;-)]
Se usi un PIC (Brrr!) sei limitato e in molti casi nemmeno disponi di un 
compilatore
decente. Se usi una CPU pontente (non solo x86, ma anche un PPC o un ARM 
o altro), in
*generale* non c'e' bisogno di usare l' assembly, se non per qualche 
parte moolto limitata.
Qui la differenza *grossa* la fa l' piu' ambiente operativo, ovvero se 
ti necessita un hard
real time o no. Nel primo caso, o risolvi di non usare un SO e fai tutto 
da te, ( limitandosi ad
 una applicazione ad oc), o usi un SO (hard) Real time, con tutti i 
servizi addizionali
(gestione disco, grafica, etc..) che ti puo' dare.
Avendo gestito un motore brushless in una stazione basata su ppc a 400MHz
(con grafica, rete, USB etc..) con  un periodo di controllo a 50us, 
tutto il suo
bel PID (loop di corrente e velocita'), abbiamo dovuto scrivere solo due 
(2) funzioncine
in assembly e solo per accedere ad un registro particolare....
A conti fatti, l' assembler serve solo a una limitatissima porzione di 
professionisti,
poi che uno voglia impararselo, bene&meglio. Pero' non basta, specie con 
CPU potenti e
sofisticate: e' *necessario* anche studiarsi l' architettura della CPU 
se no',
come gia' detto da altri, con l' asm si rischia di pessimizzare il 
proprio codice.
Una parola sui compilatori: e' vero che sono parecchio migliorati, ma sempre
scritti da persone sono. E' anche vero che c'e' ancora molto da migliorare e
che una persona con *ottima* conoscenza della CPU puo' scrivere un 
programma
assembly migliore di quello che produrrebbe un compilatore....
Da quello che ho visto, si puo' migliorare di un 10/15% in spazio codice 
/velocità...
ma....ne vale la pena?
Ottieni un codice spesso non portabile e legato ad una specifica 
applicazione,
ci devi spendere molto piu' tempo, e sopratutto la manutenzione puo' 
diventare
problematica....
B.

 "BASSO" riesco ancora a sorprendere, se non altro per le idee!
Affatto. O meglio, nel mio particolare caso è vero. Penso che se cerchi
informazioni su di me in rete non farai fatica a scoprire che sono
piuttosto legato alla comunità Python.
Ma in questo discorso, Python ha poco a vedere. Va benissimo pensare a
C++ come linguaggio di riferimento. 
Il problema è che proprio da programmatore C++ di (discreta?)
esperienza, posso dire che il modo migliore per ottimizzare le
performance è conoscere *bene* C++ e la libreria standard. E il fatto è
che, normalmente, le performance sono abbastanza buone così come sono,
semplicemente scrivendo bene il codice con un po' di attenzione.
Incidentalmente del codice ben scritto è anche relativamente facile da
verificare la correttezza. Codice veloce e non corretto non serve a
nessuno.
Spesso cambiare contenitore e/o algoritmo e/o trade-off memoria/cpu è
sufficiente.
-- 
-riko