2012-12-25 7 views
5

Ho il codice assembly di un codice che verrà eseguito in un punto del programma. Non conosco l'indirizzo del codice in memoria.Interruzione dell'istruzione con codice operativo specifico in gdb

È possibile eseguire un'interruzione di gdb quando l'istruzione corrente corrisponde a un'istruzione immessa?

Ad esempio voglio gdb rompere ogni volta che gdb raggiunge questa istruzione:

leaq  0x000008eb(%rip),%rax 

risposta

2

No, questo non è possibile e che sarebbe anche molto inefficiente da implementare.

di Debugger tipicamente supportano due tipi di punti di interruzione:

  • Hardware punti di interruzione: Il debugger chiede la CPU di sollevare una speciale interrupt eccezione quando si verifica un evento, come una locazione di memoria viene modificata.
  • Software Breakpoint: Il debugger sostituisce il codice operativo presso l'indirizzo del punto di interruzione con uno speciale istruzione "trappola" (int 3/0xcc sull'architettura x86).

La corrispondenza dell'opcode dell'istruzione corrente richiederebbe il supporto CPU per inserire un punto di interruzione hardware o il debugger deve conoscere l'indirizzo per utilizzare un punto di interruzione software.

In teoria, il debugger può semplicemente cercare l'intera memoria per la sequenza di byte dell'istruzione, ma poiché la sequenza di byte potrebbe verificarsi anche nel mezzo di un'istruzione o di dati, potrebbe ottenere falsi positivi.

Poiché le istruzioni di assemblaggio sono di lunghezza variabile, il controllo può passare a qualsiasi indirizzo arbitrario o il codice potrebbe modificarsi, non è banale smontare un'intera regione di memoria per trovare istruzioni particolari.

Quindi, in pratica, l'unico modo per trovare in modo affidabile l'istruzione nel codice di assemblaggio arbitrario sarebbe il singolo passo al livello di istruzione. E ciò sarebbe estremamente costoso, anche una semplice chiamata di libreria come printf() potrebbe richiedere minuti sull'hardware di oggi se si eseguono tutte le istruzioni.

+0

* "... e sarebbe anche molto inefficiente da implementare." * - Non sono sicuro di questo. Un'implementazione ingenua può essere inefficiente, come la comparazione delle stringhe di ogni comando mnemonico quando eseguito. Ma chiedere a GDB di fare ciò che ha suggerito il russo impiegato sembra ragionevole. Nel mio caso, voglio interrompere le chiamate a 'CPUID'. Ci sono solo quattro o cinque chiamate, quindi sembra che GDB stia facendo ciò che il russo impiegato suggerisce sarebbe perfetto per me, quindi non devo perdere tempo. – jww

2

I don't know the address of the code in memory.

Cosa ti impedisce di trovare quell'indirizzo? Eseguire objdump -d, trovare l'istruzione di interesse, annotare il suo indirizzo. Problema risolto? (Questo è banalmente esteso anche alle librerie condivise.)

+1

È un plugin QuickLook, quindi non so come viene caricato e chiamato. – Tyilo

+0

Cosa impedisce a GDB di farlo per noi? I computer dovrebbero semplificarci la vita, non più difficile :) – jww

6

Come è già stato detto, è probabilmente impossibile farlo in modo efficiente perché non c'è supporto hardware.

Ma se si vuole veramente farlo, questo comando Python può servire come punto di partenza:

class ContinueI(gdb.Command): 
    """ 
Continue until instruction with given opcode. 

    ci OPCODE 

Example: 

    ci callq 
    ci mov 
""" 
    def __init__(self): 
     super().__init__(
      'ci', 
      gdb.COMMAND_BREAKPOINTS, 
      gdb.COMPLETE_NONE, 
      False 
     ) 
    def invoke(self, arg, from_tty): 
     if arg == '': 
      gdb.write('Argument missing.\n') 
     else: 
      thread = gdb.inferiors()[0].threads()[0] 
      while thread.is_valid(): 
       gdb.execute('si', to_string=True) 
       frame = gdb.selected_frame() 
       arch = frame.architecture() 
       pc = gdb.selected_frame().pc() 
       instruction = arch.disassemble(pc)[0]['asm'] 
       if instruction.startswith(arg + ' '): 
        gdb.write(instruction + '\n') 
        break 
ContinueI() 

Basta fonte con:

source gdb.py 

e utilizzare il comando come:

breaki mov 
breaki callq 

e vi verrà lasciata l'istruzione pugno eseguita con un determinato codice operativo.

TODO: questo ignorerà gli altri punti di interruzione.

Per il caso particolare dei comuni syscall, si può usare catch syscall: https://reverseengineering.stackexchange.com/questions/6835/setting-a-breakpoint-at-system-call

+0

* "è probabilmente impossibile farlo in modo efficiente perché non c'è supporto hardware ...." * - non c'è supporto hardware da interrompere su un nome di funzione, ma GDB riesce a fallo. – jww

+0

@jww, a rigor di termini, hai ragione, ma penso che sia chiaro cosa intendo: GDB potrebbe ovviamente analizzare l'intera sezione di testo e mettere i breakpoint del software su tutti gli opcode, e questo è facile da fare in Python. Oppure puoi fare un solo passo come sto facendo. Ma ci vorrà molto più tempo che passare attraverso la tabella dei simboli per trovare alcune funzioni e mettere lì i breakpoint. Inoltre, ci saranno migliaia di codici opcode vs un nome di funzione, quindi l'esecuzione sarà lenta anche se si inseriscono i breakpoint in precedenza. –

+0

@jww Penso anche che questo sia degno di nota perché sarebbe fattibile avere il supporto hardware perché il processore già analizza gli opcode. Ma per i breakpoint delle funzioni di supporto hardware, sarebbe necessario un processore di parsing ELF :-) –

Problemi correlati