Con linguaggi di macchine virtuali basati su bytecode come Java, VB.NET, C #, ActionScript 3.0, ecc., A volte senti parlare di quanto sia facile scaricare un decompilatore da Internet, eseguire il bytecode attraverso di esso una buona volta e spesso, viene fuori qualcosa di non troppo lontano dal codice sorgente originale in pochi secondi. Presumibilmente questo tipo di linguaggio è particolarmente vulnerabile a questo.
Di recente ho iniziato a chiedermi perché non senti di più su questo riguardo al codice binario nativo, quando almeno sai in quale lingua è stato scritto in origine (e quindi in quale lingua provare a decompilare). Per molto tempo, ho pensato che fosse solo perché il linguaggio macchina nativo è molto più folle e più complesso del tipico bytecode.
Ma che aspetto ha il bytecode? Sembra così:
1000: 2A 40 F0 14
1001: 2A 50 F1 27
1002: 4F 00 F0 F1
1003: C9 00 00 F2
E come appare il codice macchina nativo (in esadecimale)? Ovviamente, assomiglia a questo:
1000: 2A 40 F0 14
1001: 2A 50 F1 27
1002: 4F 00 F0 F1
1003: C9 00 00 F2
E le istruzioni provengono da uno stato d'animo un po 'simile:
1000: mov EAX, 20
1001: mov EBX, loc1
1002: mul EAX, EBX
1003: push ECX
Quindi, dato il linguaggio per provare a decompilare un binario nativo, diciamo C ++, cosa c'è di così difficile? Le uniche due idee che mi vengono subito in mente sono 1) è davvero molto più intricato del bytecode, o 2) qualcosa sul fatto che i sistemi operativi tendono a impaginare i programmi e spargere i loro pezzi causa troppi problemi. Se una di queste possibilità è corretta, spiega. Ma in entrambi i casi, perché non ne hai mai sentito parlare?
NOTA
Sto per accettare una delle risposte, ma prima voglio menzionare qualcosa. Quasi tutti fanno riferimento al fatto che diversi pezzi di codice sorgente originale potrebbero essere associati allo stesso codice macchina; i nomi delle variabili locali vengono persi, non si conosce il tipo di loop originariamente utilizzato, ecc.
Tuttavia esempi come i due che sono stati appena citati sono in qualche modo banali ai miei occhi. Alcune delle risposte tendono tuttavia a affermare che la differenza tra il codice macchina e l'origine originale è drasticamente molto più di qualcosa di così banale.
Ma per esempio, quando si tratta di cose come nomi di variabili locali e tipi di loop, anche il bytecode perde queste informazioni (almeno per ActionScript 3.0). Ho già recuperato quella roba attraverso un decompilatore prima e non mi importava davvero se una variabile fosse chiamata strMyLocalString:String
o loc1
. Potrei ancora guardare in quel piccolo ambito locale e vedere come viene utilizzato senza troppi problemi. E un for
loop è praticamente la stessa cosa esatta di awhile
loop, se ci pensate. Inoltre, anche quando eseguivo il sorgente tramite irrFuscator (che, a differenza di secureSWF, non fa molto di più che randomizzare i nomi di variabili e funzioni dei membri), sembra comunque che potresti iniziare a isolare determinate variabili e funzioni in classi più piccole, figura scoprire come vengono utilizzati, assegnare loro i tuoi nomi e lavorare da lì.
Affinché questo sia un grosso problema, il codice macchina dovrebbe perdere molte più informazioni di così, e alcune delle risposte vanno in questo.