Domanda:
Ida Pro: analizzare l'espressione di operandi complessi utilizzando Idapython
langlauf.io
2015-06-01 19:00:03 UTC
view on stackexchange narkive permalink

Supponiamo che sia stata data la seguente riga in Ida Pro:

  mov [rsp + 3F8h + var_3F8], 0  

Come posso analizzare e accedere al elementi all'interno di [] ? Cosa ho provato:

  • idc.GetOpnd (addr, n) # restituisce una stringa " [rsp + 3F8h + var_3F8] "
  • idc.GetOperandValue (addr, n) # restituisce 4 , che è spiegato nel idc.py come segue

def GetOperandValue (ea, n): "" "
Ottieni il numero utilizzato nell'operando

Questa funzione restituisce un numero immediato utilizzato nell'operando

@param ea: indirizzo lineare dell'istruzione @param n: il numero dell'operando

@return:

valore operando è un valore immediato => valore immediato

operando ha uno spostamento => spostamento

operando è un riferimento di memoria diretto => indirizzo di memoria

l'operando è un registro => numero di registro

l'operando è una frase di registro => numero di frase

altrimenti => -1 "" "

Come posso accedere agli elementi della" frase ", ad esempio rsp , 3F8h e var_3F8 ? Sto cercando qualcosa del genere:

  my_op_phrase = idc.ParseOperandPhrase (ea, n) my_op_phrase [0] # -> 'rsp'my_op_phrase [0] .type # -> idaapi.o_regrase [1] # -> 0x3F8hmy_op_phrase [1] .type # -> idaapi.o_immmy_op_phrase [2] # -> 'var_3F8'…   

È possibile o qualcosa di sbagliato / p>

Due risposte:
Guntram Blohm supports Monica
2015-06-01 19:17:14 UTC
view on stackexchange narkive permalink

Nota che l'istruzione assembly originale era probabilmente mov [rsp + 4], 0 (*). Questo è il motivo per cui idc.GetOperandValue restituisce 4.

Soprattutto con i compilatori meno recenti, che utilizzavano molto push e pop , il valore di rsp varia notevolmente durante l'esecuzione di una funzione. Ciò che è esp + 8 ora sarebbe esp + 12 dopo un push; quello che sarebbe rsp + 8 ora sarebbe rsp dopo un pop. Quindi, durante la lettura di un pezzo di codice assembly (semplice) è molto difficile tenere traccia di quale posizione dello stack si accede quando.

(Questo è stato migliorato di recente; x64 abis usa i registri per passare i parametri quindi il codice non Non spingere e pop più tanto, e compilatori come gcc fanno abbastanza spazio nello stack e inseriscono direttamente i parametri negli indirizzi relativi a esp anche a 32 bit, quindi esp / rsp non cambia più di tanto. Ma c'è ancora molto vecchio codice da invertire.)

Per migliorare la situazione, IDA assegna nomi di variabili alle posizioni dello stack, come il tuo var_3F8 . Ogni volta che un'istruzione esegue un indirizzamento relativo sp , IDA utilizza il nome della variabile ed emette un offset aggiuntivo per tenere conto delle modifiche allo stack pointer dall'inizio della funzione. Quindi, se il tuo codice originale è simile a

  mov [rsp + 8], raxsub rsp, 128mov [rsp + 136], rbxpush rcxmov [rsp + 144], rdx  

accede in ogni caso allo stesso indirizzo di memoria. Ida lo converte in

  mov [rsp + 0 + var_8], raxsub rsp, 128mov [rsp + 128 + var_8], rbxpush rcxmov [rsp + 136 + var_8], rdx  

Tuttavia, queste modifiche sono solo visualizzate, non cambiano il tuo binario! Il recupero degli operandi restituirà ancora 8 , 136 e 144 , non i valori che ida ti mostra.

Se desideri analizzarlo automaticamente, puoi tenere traccia dell'offset del puntatore dello stack e regolare il risultato di GetOperandValue di conseguenza, o dovrai usare le funzioni stringa python sull'output di GetOpnd , buttare via la parte centrale e confrontare la parte giusta (i nomi delle variabili).

(*) che sembra un po 'strano ora che ci penso, dato che ovviamente stai usando 64 bit, poiché il tuo puntatore allo stack è rsp , che suggerirebbe un allineamento di 8 byte.

È questo il "delta dello stack corrente" a cui ti riferisci? Può essere recuperato con `GetSpd`.
@Guntram Blohm: Sei sicuro del motivo per cui "GetOperandValue ()" restituisce 4? "Idc.py" dice: "l'operando è una frase di registro => numero di frase". Lo intendo come: "se c'è una 'frase' di registro,` GetOperandValue () `restituisce il * numero della frase *." Non so però cosa si intenda con questo * numero di frase *. Cosa pensi?
Al momento non ho accesso al computer del mio ufficio, dove è installato IDA, ma presumo che "register phrase" sia quasi uguale a "register name", quindi a ogni registro del processore viene assegnato un numero e ida restituisce quel numero se l'operando è un nome di registro, o qualcosa di simile che denota un registro su hardware esotico.
Jason Geffner
2015-06-01 19:22:44 UTC
view on stackexchange narkive permalink

Supponendo che addr sia l'EA di mov [rsp + 3F8h + var_3F8], 0 :

  re.findall ('\ [(. *) \] ', idc.GetDisasm (addr)) [0] .split (' + ')  

restituisce l'elenco

  ["rsp", "3F8h", "var_3F8"]  
Funziona finché non premi una sottrazione o moltiplicazione, ad es. `mov edx, [eax + ecx * 4]`. Regex non è davvero un'ottima opzione qui, ma sfortunatamente non sembra che IDA ci offra davvero molta scelta.
_ "Funziona fino a quando non ottieni una sottrazione o una moltiplicazione" _ - Sì, ma non è quello che ti ha chiesto :)
@JasonGeffner ** (a) ** Più facile da eseguire regex `GetOpnd (ea, 0)` == `[rsp + 3F8h + var_3F8]` ** (b) ** Come ottenere il valore di var_x (* indovinabile *) e arg_x (* non su molto) ** (c) ** In casi come questi (* register + displacement *) solo `GetOperandValue (ea, 1) if GetOpType (ea, 1) == o_displ else None` == "48".
@Polynomial: quel tipo di operando può essere rilevato da `GetOpnd (ea, 1) == o_phrase` ed è probabilmente l'unico tipo di operando per il quale useresti regex, tranne forse per o_displ. Sebbene, poiché non è possibile risolverlo su un valore effettivo, probabilmente non è probabile che diventi mai un problema.


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...