Perché non possiamo capire il contenuto di un file binario dopo la compilazione?


10

Per quanto ne so, ogni programma è costituito da un pacchetto di istruzioni del processore con alcune variabili di dati specifici (float, int, char ...) per lavorare sui registri del processore .

Quindi, la prima cosa che ci ho pensato (molto tempo fa) è che se sai che il valore ASCII di %¨#$¨#(solo un esempio casuale) potrebbe essere interpretato come l'indirizzo del registro puntatore dello stack (solo esemplificativo) di un x86 processore. Se questo è vero, ogni volta che si trova questo valore "illeggibile" durante la lettura del contenuto di un file binario, è possibile interpretare che il registro puntatore dello stack viene utilizzato per gestire alcune variabili di dati.

Purtroppo questo non succede. Di seguito, c'è un esempio del contenuto del ping.exeprogramma di Windows aperto con notepad.exe:

Ping.exe come visualizzato in Blocco note MS

È un file binario e i suoi dati sono incomprensibili per noi umani (è comprensibile per le macchine.) Non ha alcun senso per nessuno anche se conoscono il codice assembly (il livello più basso del linguaggio macchina).

Quindi, se ho capito tutto correttamente, qualcuno potrebbe spiegare

  1. Perché un codice binario non può tornare al codice Assembly nella misura in cui sono, in fondo, la stessa cosa?
  2. Se si può capire il codice assembly, perché il binario compilato risultante da questo codice non è più "leggibile"?

12
Puoi, hai solo bisogno di un disassemblatore .
David Schwartz,

Quindi posso smontare qualsiasi file .exe ??? Sapevo solo che funziona con il codice gestito ...
Diogo,

13
Puoi disassemblare qualsiasi eseguibile. Se riesci a dare un senso all'uscita disassemblata è un'altra storia.
David Schwartz,

5
La compilazione o l'assemblaggio rimuove molte informazioni significative dal punto di vista umano come nomi di variabili, etichette di rami, ecc. Lo smontaggio ottiene il flusso di istruzioni, ma hai ancora molto da capire.
mpez0,

1
Anche l' offuscamento del codice può ostacolare lo smontaggio.
matematica

Risposte:


12

Innanzitutto, i registri non hanno indirizzi. Ogni istruzione in qualsiasi linguaggio assembly si traduce in un codice operativo. I codici operativi in ​​x86 possono essere uno, due, tre o anche più byte (in alcuni altri processori sono "a larghezza fissa"). Di solito il codice operativo identifica l'istruzione, la modalità di indirizzamento e i registri coinvolti. La "modalità di indirizzamento" determina se la CPU richiede più del codice operativo, ovvero la modalità di indirizzamento "immediata" significa che ci sono dati aggiuntivi subito dopo (o "immediatamente dopo") l'istruzione per tale istruzione - le modalità di indirizzamento "assoluto" indicano che un l'indirizzo di memoria segue le istruzioni e viene utilizzato da tale istruzione.

Puoi scoprire il codice operativo di qualcosa di simile MOV AL,SPo simile e quindi cercarlo. x86 ha molte istruzioni che operano sul puntatore dello stack.

Ma per favore, si prega di smettere di usare il Blocco note e utilizzare un editor esadecimale, invece. Consiglierei HxD, anche se ce ne sono molti altri.

E @David Schwartz è corretto. Un disassemblatore eseguirà l'iterazione attraverso un file e tradurrà i codici operativi in ​​testo leggibile. Quello che vuoi fare è totalmente possibile.

Tuttavia, è necessario sapere dove iniziano le istruzioni nel file perché, se si inizia con l'indirizzo errato, alcuni dati che dovrebbero essere gli "operandi" per gli opcode (come le istruzioni che accettano un indirizzo per un operando o un "argomento") potrebbero vengono interpretati erroneamente come codici operativi. Sapere questo richiede la conoscenza del formato dell'eseguibile, che è per Windows il "Portable Executable" o il formato PE (ed è spesso ELF per sistemi Linux). Sono sicuro che ci sono disassemblatori che capiscono PE, ecc., Ma non conosco nessuno.


1
IDA è uno dei dissemblatori PE più comuni. Funziona anche con file Linux e Mac. La versione 5.0 è ancora disponibile come freeware
Scott Chamberlain il

1
> se inizi con l'indirizzo sbagliato, ... potrebbe essere interpretato male. Questo è il motivo per cui tutte le %¨#$¨#occorrenze di non saranno necessariamente un riferimento allo stack-pointer; potrebbe essere solo al centro di due diversi comandi : _3p%¨#e $¨#b5F( _3p   %¨#$¨#   b5F).
Synetech,

11

Quindi, se ho capito tutto correttamente

Non proprio.

È un file binario e i suoi dati sono incomprensibili per noi umani

In genere un file binario è incomprensibile per uomo e macchina, specialmente quando lo scopo del file è sconosciuto. Si noti che non tutti i file binari sono file eseguibili. Molti file binari sono file di dati che non contengono istruzioni per la macchina. Questo è il motivo per cui le estensioni dei file vengono utilizzate durante la denominazione dei file (in alcuni sistemi operativi). Il . l' estensione CP è stata utilizzata da CP / M per indicare un file eseguibile. Il . MS-DOS ha aggiunto l'estensione exe per indicare un altro formato di file eseguibile. * nix utilizza l'attributo execute per indicare quali file possono essere eseguiti, sebbene possano essere sia script che codice.

Come già accennato da altri, i file binari, che contengono numeri, dovrebbero essere visualizzati da un programma di dump esadecimale o da un editor esadecimale e non da un visualizzatore di testo.

c'è un esempio del contenuto del programma ping.exe

Quel file è in realtà un programma trasferibile e non tutti i dati in quel file rappresentano il codice macchina. Ci sono informazioni sul programma come quali librerie dinamiche di cui ha bisogno, quali routine devono essere collegate, requisiti per stack e memoria del programma e dei dati, e il punto di ingresso del programma. Gli operandi di indirizzo nel file potrebbero essere valori relativi che devono essere calcolati in valori assoluti o riferimenti che devono essere risolti.

Il "file di programma" a cui probabilmente stai pensando è chiamato un file di immagine binario o un dump della memoria del programma. Tale file conterrebbe solo codice e dati macchina, con tutti i riferimenti di indirizzo impostati correttamente per l'esecuzione.

anche se conoscono il codice assembly (il livello più basso del linguaggio macchina).

Il linguaggio assembly non è lo stesso del linguaggio macchina . La CPU tipica (per escludere i computer di linguaggio di alto livello) accetta il codice macchina come input, un'istruzione alla volta. Gli operandi sono registri o indirizzi di memoria numerici. Il linguaggio assembly è un linguaggio di livello superiore che può utilizzare etichette simboliche per posizioni e variabili delle istruzioni, oltre a sostituire i codici operativi numerici con mnemonici. Un programma di linguaggio assembly deve essere convertito in linguaggio / codice macchina prima di poter essere effettivamente eseguito (in genere da utility chiamate assembler, linker e loader).

L'operazione inversa, lo smontaggio, può essere eseguita su file di programma con esito positivo e perdita di informazioni simboliche. Il disassemblaggio di un dump della memoria o di un file di immagine del programma comporta ulteriori tentativi ed errori, poiché i percorsi di codice e dati devono essere identificati manualmente.

A proposito ci sono persone che possono leggere e codificare il codice macchina (numerico). Naturalmente questo è molto più semplice su una CPU o microcontrollore a 8 bit rispetto a un processore CISC a 32 bit con una dozzina di modalità di indirizzo di memoria.


2

Non è possibile visualizzare la codifica corretta e prevista di un file binario tramite Blocco note. Si prega di rivedere questo per riferimento futuro. La maggior parte dei programmi di modifica del testo non analizza i formati di codifica binaria e si prevede che analizzerà la formattazione del codice di caratteri ASCII.

Quindi l'apertura di un file binario in un editor di testo produrrà caratteri ASCII equivalenti che non hanno alcun senso del formato originale dei dati binari analizzati dall'editor di testo. Come accennato, gli editor esadecimali e alcuni hanno funzionalità binarie, per visualizzare i contenuti in puro formato binario.

È errato che non è possibile comprendere il contenuto di un file binario. Sebbene siano difficili e nelle architetture informatiche moderne estremamente difficili da smontare a mano dal solo binario alle istruzioni appropriate riconosciute dalla CPU per l'esecuzione (o CPU emulata / virtuale), ecc., Può essere fatto.

Come pensi che siano programmati gli emulatori? Lo sviluppatore dovrebbe conoscere i codici operativi per essere in grado di programmare il sistema fittizio affinché riconosca e si comporti come l'hardware reale farebbe in qualche modo. Le documentazioni spiegano molte architetture di CPU e persino le GPU le hanno (anche se più riservate).

Un'altra cosa da notare è che nel livello più basso, sebbene correlativo, i "dati binari" non sono in realtà un mucchio di zero e uno, ma tensioni di alta e bassa amplificate / commutate attraverso un circuito elettrico come corrente.

Di solito il binario è 1: 1, quindi ha molto senso usare il sistema numerico per questo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.