2011-11-02 13 views
8

Attualmente sto utilizzando uno schema di sostituzione del codice in 32 bit in cui il codice che viene spostato in un'altra posizione, legge variabili e un puntatore di classe. Poiché x86_64 non supporta l'indirizzamento assoluto, ho problemi a trovare gli indirizzi corretti per le variabili nella nuova posizione del codice. Il problema in dettaglio è che, a causa del relativo indirizzamento dell'istruzione, l'indirizzo del puntatore dell'istruzione è diverso rispetto al momento della compilazione.Indirizzamento assoluto per la sostituzione del codice runtime in x86_64

Quindi esiste un modo per utilizzare l'indirizzamento assoluto in x86_64 o un altro modo per ottenere gli indirizzi di variabili non relative al puntatore dell'istruzione?

Qualcosa come: leaq variable(%%rax), %%rbx sarebbe anche di aiuto. Voglio solo non avere alcuna dipendenza dal puntatore dell'istruzione.

risposta

6

Provare a utilizzare il modello di codice di grandi dimensioni per x86_64. In gcc, questo può essere selezionato con -mcmodel = large. Il compilatore utilizzerà l'indirizzamento assoluto a 64 bit per codice e dati.

È inoltre possibile aggiungere -fno-pic per disabilitare la generazione del codice indipendente dalla posizione.

Edit: costruire un piccolo test app con -mcmodel = grande e il binario risultante contiene sequenze come

400b81:  48 b9 f0 30 60 00 00 movabs $0x6030f0,%rcx 
400b88:  00 00 00 
400b8b:  49 b9 d0 09 40 00 00 movabs $0x4009d0,%r9 
400b92:  00 00 00 
400b95:  48 8b 39    mov (%rcx),%rdi 
400b98:  41 ff d1    callq *%r9 

che è un carico di 64 bit assoluto immediata (in questo caso un indirizzo) seguito da una chiamata indiretta o un carico indiretto. La sequenza di istruzioni

moveabs variable, %rbx 
addq %rax, %rbx 

è l'equivalente di un "leaq offset64bit (% rax),% rbx" (che non esiste), con alcuni effetti collaterali come bandiera cambiando ecc

+0

, il metodo -mcmodel = large dovrebbe essere la soluzione. devo indagare sul perché il compilatore gcc osx non lo supporta – nux

+0

Forse è troppo vecchio. I modelli piccoli (standard) e di codice medio sono stati aggiunti presto, il modello più grande è venuto dopo. – hirschhornsalz

+0

ti ringrazio tanto questo sembra molto buono e risolve definitivamente il problema di indirizzamento assoluto – nux

2

Quello che stai chiedendo è fattibile, ma non molto facile.

Un modo per farlo è compensare lo spostamento del codice nelle sue istruzioni. È necessario trovare tutte le istruzioni che utilizzano l'indirizzamento relativo al RIP (hanno il byte ModRM di 05h, 0dh, 15h, 1dh, 25h, 2dh, 35h o 3dh) e regolano il loro campo disp32 in base alla quantità di spostamento (la mossa è quindi limitato a +/- 2 GB nello spazio degli indirizzi virtuali, che potrebbe non essere garantito dato che lo spazio degli indirizzi a 64 bit è maggiore di 4 GB).

È possibile anche sostituire quelle istruzioni con i loro equivalenti, molto probabilmente sostituendo ogni istruzione originale con più di uno, per esempio:

; These replace the original instruction and occupy exactly as many bytes as the original instruction: 
    JMP Equivalent1 
    NOP 
    NOP 
Equivalent1End: 

; This is the code equivalent to the original instruction: 
Equivalent1: 
    Equivalent subinstruction 1 
    Equivalent subinstruction 2 
    ... 
    JMP Equivalent1End 

Entrambi i metodi richiedono almeno alcune routine x86 smontaggio rudimentali.

Il primo può richiedere l'uso di VirtualAlloc() su Windows (o qualche equivalente su Linux) per garantire che la memoria che contiene la copia patchata del codice originale sia compresa tra +/- 2 GB di quel codice originale. E l'allocazione a indirizzi specifici può ancora fallire.

Quest'ultimo richiederà più di un semplice smontaggio primitivo, ma anche una decodifica e generazione di istruzioni complete.

Potrebbero esserci altre stranezze da aggirare.

confini istruzioni possono anche essere trovati impostando il flag TF nel registro RFLAGS per rendere la CPU genera l'interrupt single-step di debug al termine dell'esecuzione di ogni istruzione. Un gestore di eccezioni di debug dovrà catturarle e registrare il valore di RIP dell'istruzione successiva. Credo che questo possa essere fatto usando Structured Exception Handling (SEH) in Windows (mai provato con le interruzioni di debug), non sono sicuro di Linux. Affinché questo funzioni, dovrai eseguire tutto il codice, ogni istruzione.

Btw, c'è l'indirizzamento assoluto in modalità 64 bit, vedere, ad esempio, le istruzioni MOV da/accumulatore con opcode da 0A0h a 0A3h.

+0

grazie per la risposta . per quanto ho capito, l'approccio è ricalcolare il valore dell'indirizzo per i mov in fase di runtime. Questo sembra pesante per lo schema, quindi se questo è l'unico modo per pensare a un'implementazione differente, – nux