2012-12-25 8 views
5

Mam kod zestawu kodu, który zostanie wykonany w punkcie programu. Nie znam adresu kodu w pamięci.Instrukcja przerwania z określonym kodem operacji w gdb

Czy można zrobić przerwę gdb, gdy aktualna instrukcja pasuje do wprowadzonej instrukcji?

Na przykład chcę gdb gdb złamać gdy osiągnie tę instrukcję:

leaq  0x000008eb(%rip),%rax 

Odpowiedz

2

Nie, to nie jest możliwe i byłoby bardzo nieefektywne do wdrożenia.

Debugger na ogół obsługują dwa rodzaje przerwań:

  • Hardware breakpoints: Debuger pyta CPU podnieść specjalny przerwanie wyjątku, gdy wystąpi jakieś zdarzenie, jak pewnego miejsca w pamięci ulegnie zmianie.
  • Software Breakpoints: Debuger zastępuje opcodu na adres Breakpoint ze specjalną instrukcją "trap" (int 3/0xcc na architekturze x86).

Dopasowanie kodu operacji instrukcji bieżącej wymaga albo obsługi procesora, aby wstawić punkt przerwania sprzętowego, albo debugger musi znać adres, aby użyć punktu przerwania oprogramowania.

Teoretycznie debugger mógłby po prostu przeszukać całą pamięć dla sekwencji bajtów instrukcji, ale ponieważ sekwencja bajtów może również wystąpić w środku instrukcji lub danych, może uzyskać fałszywe alarmy.

Ponieważ instrukcje dotyczące montażu mają zmienną długość, kontrola może przejść do dowolnego adresu lub kod sam się modyfikuje, nie jest też trywialne zdemontowanie całego obszaru pamięci w celu znalezienia konkretnej instrukcji.

W zasadzie jedynym sposobem niezawodnego znalezienia instrukcji w dowolnym kodzie montażu byłby pojedynczy krok na poziomie instrukcji. Byłoby to niezwykle kosztowne, nawet banalne wywołanie biblioteki, takie jak printf(), mogłoby zająć kilka minut na dzisiejszym sprzęcie, jeśli wykonasz jedną instrukcję krok po kroku.

+0

* „... i byłoby bardzo nieefektywne do wdrożenia.” * - Nie jestem tego pewien. Naiwna implementacja może być nieskuteczna, podobnie jak ciąg porównywania każdego mnemonika po uruchomieniu. Ale prośba GDB o zrobienie tego, co zaproponował rosyjski pracownik, wydaje się rozsądna. W moim przypadku chcę przerwać połączenia do 'CPUID'. Jest tylko cztery lub pięć połączeń do niego, więc wygląda na to, że GDB robi to, co sugerował Employed Russian, więc nie muszę tracić czasu. – jww

2

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

Co uniemożliwia znalezienie tego adresu? Uruchom objdump -d, znajdź interesujące Cię polecenie, zanotuj jego adres. Problem rozwiązany? (Jest to trywialnie rozszerzone na biblioteki współdzielone).

+1

Jest to wtyczka QuickLook, więc nie wiem, jak została załadowana i wywołana. – Tyilo

+0

Co powstrzymuje GDB przed zrobieniem tego dla nas? Komputery powinny ułatwiać nam życie, a nie być trudniejsze :) – jww

6

Jak powiedzieli inni, prawdopodobnie nie da się tego zrobić skutecznie, ponieważ nie ma wsparcia sprzętowego.

Ale jeśli naprawdę chcesz to zrobić, to polecenie Python może służyć jako punkt wyjścia:

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() 

Tylko źródło go z:

source gdb.py 

i użyj polecenia jak:

breaki mov 
breaki callq 

i zostaniesz na pierwszej instrukcji wykonanej z danym kodem operacji.

TODO: zignoruje to pozostałe punkty przerwania.

Dla konkretnego przypadku wspólnego syscall, można użyć catch syscall: https://reverseengineering.stackexchange.com/questions/6835/setting-a-breakpoint-at-system-call

+0

* "prawdopodobnie nie da się tego zrobić wydajnie, ponieważ nie ma wsparcia sprzętowego ...." * - nie ma wsparcia sprzętowego, aby złamać nazwę funkcji, ale GDB udaje się Zrób to. – jww

+0

@jww Ściśle mówiąc masz rację, ale myślę, że jest jasne, co mam na myśli: GDB może oczywiście parsować całą sekcję tekstową i umieszczać punkty przerwania oprogramowania na wszystkich tych opkodach, i to jest łatwe do zrobienia w Pythonie. Lub możesz zrobić pojedynczy krok, tak jak ja. Ale to zajmie znacznie więcej czasu niż przechodzenie przez tabelę symboli, aby znaleźć kilka funkcji i umieścić tam punkty przerwania. Ponadto będą tysiące opcodes vs jedna nazwa funkcji, więc wykonanie będzie wolne, nawet jeśli wcześniej umieściłeś punkty przerwania. –

+0

@jww Również myślę, że warto o tym wspomnieć, ponieważ byłoby możliwe posiadanie wsparcia sprzętowego, ponieważ procesor już parsuje opkody. Ale do punktów obsługi funkcji wsparcia sprzętowego, wymagałoby procesora analizowania ELF :-) –