Domanda:
Come recuperare le variabili da un codice assembly?
perror
2013-03-26 21:31:58 UTC
view on stackexchange narkive permalink

Supponendo di avere un codice assembly, quali sono le tecniche note che potrebbero essere utilizzate per recuperare le variabili utilizzate nel codice di alto livello originale?

Modifica : da recupero di variabili , non intendo recupero di nomi di variabili , ma cercando di identificare posizioni di memoria che vengono utilizzate per memorizzare risultati temporanei che potrebbero essere sostituiti da una variabile nel codice di alto livello . Inoltre, non sto parlando di bytecode, ma di codice binario reale senza informazioni sul tipo, né nomi completi incorporati in esso.

Quattro risposte:
#1
+15
Igor Skochinsky
2013-03-27 05:49:06 UTC
view on stackexchange narkive permalink

(Avevo intenzione di renderlo un commento, ma è risultato piuttosto lungo e fornisce una risposta da solo)

Alcuni dei commenti menzionavano il decompilatore Hex-Rays. Le sue idee di base non sono un segreto commerciale e sono infatti descritte nel white paper di Ilfak Guilfanov che accompagna la presentazione che ha tenuto nel 2008.

Incollerò qui la parte rilevante:

Allocazione di variabili locali

Questa fase utilizza l'analisi del flusso di dati per connettere registri da diversi blocchi di base al fine di convertirli in locali variabili. Se un registro è definito da un blocco e utilizzato da un altro, creeremo una variabile locale che copre sia la definizione che l'uso. In altre parole, una variabile locale è composta da tutte le definizioni e da tutti gli usi che possono essere collegati tra loro. Sebbene l'idea di base sia semplice, le cose si complicano a causa dei registri byte / word / dword.

È semplice in superficie ma ovviamente l'implementazione deve tenere conto di numerosi dettagli. E c'è sempre spazio per migliorare. C'è questo passaggio:

Per il momento, non analizziamo intervalli in tempo reale di variabili di stack (ciò richiede prima una buona analisi degli alias: dobbiamo essere in grado di dimostrare che una variabile di stack non è modificato tra due posizioni). Dubito che nel prossimo futuro sarà disponibile un'analisi completa dell'intervallo dal vivo per le variabili dello stack.

Quindi, per le variabili dello stack l'approccio al momento è semplice: ogni slot dello stack è considerato un singolo variabile per l'intera funzione (con alcune piccole eccezioni). Il decompilatore si basa qui sul lavoro svolto da IDA durante lo smontaggio, dove viene creato uno stack slot per ogni accesso da parte di un'istruzione.

Un problema attuale sono più nomi per la stessa variabile. Ad esempio, il compilatore può memorizzare nella cache lo stack var in un registro, passarlo a una funzione, quindi ricaricarlo in un altro registro. Il decompilatore deve essere pessimista qui. Se non siamo in grado di dimostrare che la stessa posizione contiene lo stesso valore in due punti nel tempo, non possiamo unire le variabili. Ad esempio, ogni volta che il codice passa un indirizzo di una variabile a una chiamata, il decompilatore deve presumere che la chiamata possa rovinare qualsiasi cosa dopo quell'indirizzo. Quindi, anche se il registro contiene ancora lo stesso valore dello stack var, non possiamo esserne certi al 100%. Da qui l'eccesso di nomi di variabili. L'utente può tuttavia sovrascriverlo con la mappatura manuale.

Ci sono alcune idee sull'introduzione di annotazioni di funzione che specificherebbero esattamente come una funzione utilizza e / o cambia i suoi argomenti (simile a SAL di Microsoft) che allevierebbe questo problema , ma ci sono alcuni problemi di implementazione tecnica.

Esattamente il tipo di risposta che stavo cercando, grazie!
I commenti non sono per discussioni estese; questa conversazione è stata [spostata in chat] (https://chat.stackexchange.com/rooms/93469/discussion-on-answer-by-igor-skochinsky-how-to-recover-variables-from-an-assembl) .
#2
+9
Rolf Rolles
2013-03-27 04:33:39 UTC
view on stackexchange narkive permalink

Quello che stai descrivendo è esattamente il problema che è stato affrontato da Gogul Balakrishnan nel suo lavoro di dottorato sull'analisi del set di valori [1]. In particolare, definisce un modello di memoria per x86 in termini di concetti come "posizioni astratte". Ecco la sua descrizione per quel concetto:

Come sottolineato in precedenza, gli eseguibili non hanno entità intrinseche come le variabili del codice sorgente che possono essere utilizzate per l'analisi; pertanto, il passaggio successivo consiste nel ripristinare entità di tipo variabile dall'eseguibile. Ci riferiamo a entità simili a variabili come a-loc (per "posizioni astratte").

Suona familiare alla tua domanda? Dovresti leggere questa tesi, anche se tieni presente che, come la maggior parte dei documenti sull'interpretazione astratta, è una lettura concisa e poco amichevole.

[1] http: //pages.cs.wisc. edu / ~ bgogul / Research / Thesis / thesis.html

#3
+8
endeavor
2013-03-26 22:00:06 UTC
view on stackexchange narkive permalink

Quindi ..... questo è uno dei motivi per cui l'analisi binaria è difficile , la perdita di informazioni semantiche. Una variabile non è un concetto noto nell'architettura del computer, ricorda un livello di comprensione più elevato.

La migliore risposta che posso darti è, se stai facendo Analisi dell'output del compilatore (quale sei), puoi cercare le convenzioni usate da quel compilatore per memorizzare le variabili, probabilmente come una combinazione di registri e "spillage" di variabili in posizioni sullo stack frame.

La cattiva notizia è dipende dal compilatore. La buona notizia è che la maggior parte dei compilatori è più o meno simile.

Puoi tentare di determinare la firma osservando le operazioni condizionali che funzionano su un valore (supponendo che lo sviluppatore non abbia commesso un errore come confrontando un valore con segno e senza segno).

Offri percorsi di indagine carini, ma devono esserci alcune tecniche "ad hoc" esistenti. Ad esempio, quali sono le tecniche utilizzate in [decompilatore a raggi esadecimali] (https://www.hex-rays.com/products/decompiler/) o [boomerang] (http://boomerang.sourceforge.net/) per identificare le variabili all'interno di uno stack-frame?
Il decompilatore Hex-Rays è in realtà piuttosto scarso nel comprendere i confini delle variabili. Sembra semplicemente presumere che tutto ciò che può essere una variabile lo sia. Ciò può portare a una grossolana sovrastima del numero di variabili. In genere è necessario mappare un bel po 'di variabili come alias per ottenere una decompilazione pulita. È comunque un prodotto fantastico. Igor probabilmente sa molto di più, ma questo potrebbe rasentare i segreti commerciali o qualcosa del genere.
sforzo: non solo dipendente dal compilatore, però. Considera le convenzioni di chiamata, sono dettate dall'architettura o dalla piattaforma.
@PeterAndersson: probabilmente non sarebbe nulla che rivelerebbero. Suppongo che oltre a quello che chiunque di noi potrebbe inventare, Hex-Rays (l'azienda) ha probabilmente escogitato un mucchio di euristiche per identificare le cose come questo o quello. E sono d'accordo, dopo aver testato la beta del plugin del decompilatore, non ero affatto convinto. Mi ha ingannato molto dove IDA non è mai stato. Eppure sono passati alcuni anni, ma come privato non voglio permettermelo al momento;)
@0xC0000022L, il decompilatore è fantastico. Ci fa risparmiare molto tempo. Devi solo essere abbastanza accurato nel digitare e mappare tutto. Continua a commettere errori ea volte inganna, ma è decisamente positivo.
#4
-2
samuirai
2013-03-26 22:02:40 UTC
view on stackexchange narkive permalink

Un dolce trucco per quanto riguarda le stringhe all'interno di un binario, è lo strumento da riga di comando strings . Potrebbe essere importante menzionare che non cerca "variabili". Cerca solo caratteri validi continui e li stampa. Quindi questo è utile anche per estrarre stringhe da qualsiasi tipo di file (se memorizzato in chiaro).

Programma di esempio:

  int main (int argc, char * argv [ ]) {char pw [] = "SecretPW"; if (! strcmp (pw, argv [1])) {printf ("Correct! \ n"); } else {printf ("False ... \ n"); } return 0;}  

Utilizzo di string per estrarre le stringhe:

  $ ./test FalsePWFalse ... $ strings testSecretPWCorrect! False ... $ ./test SecretPW 139 ↵Corretto!  


Questa domanda e risposta è stata tradotta automaticamente dalla lingua inglese. Il contenuto originale è disponibile su stackexchange, che ringraziamo per la licenza cc by-sa 3.0 con cui è distribuito.
Loading...