Pierwsze kroki z GNU Debuggerem na Linuksie: Przyspieszony kurs
Debugowanie jest niezbędną umiejętnością dla programistów i badaczy bezpieczeństwa. Silne zrozumienie debugowania pozwala zrozumieć plik wykonywalny na niższym poziomie i wychwycić wszelkie czające się błędy.
GNU Debugger, powszechnie określany jako GDB, jest trwałym narzędziem do debugowania, które zostało zaufane i wykorzystywane przez programistów na przestrzeni czasu. W tej sekcji zbadamy jego zastosowanie w kontekście systemów Linux.
Przygotowanie przykładowych programów
Aby zagłębić się w możliwości GDB, konieczne jest przetestowanie go przy użyciu pliku wykonywalnego, którego kod źródłowy i symbole debugowania są dostępne do zbadania. Jako przykład ilustrujący, uruchomimy GDB na dwóch różnych programach - aplikacji do sprawdzania kluczy i wielowątkowym programie, który wyświetla komunikaty na ekranie - jeden opracowany w języku C i skompilowany przy użyciu kompilatora GNU C, podczas gdy drugi nie ma kodu źródłowego.
Masz możliwość użycia dowolnego alternatywnego kompilatora C, pod warunkiem, że powstrzymasz się od usuwania metadanych pliku wykonywalnego, które zawierają informacje o pochodzeniu programu i modyfikacjach dokonanych podczas kompilacji.
Aby efektywnie korzystać z GDB, jest wysoce prawdopodobne, że będziesz go używać we własnych aplikacjach. W związku z tym należy upewnić się, że programy te są kompilowane przy użyciu flagi -g
z gcc
, która umożliwia włączenie symboli debugowania.
Rzeczywiście, gdy symbole debugowania są nieobecne, a plik binarny został znacznie zminimalizowany, należy zagłębić się w zdemontowany kod aplikacji. Takie przedsięwzięcie wymaga biegłego zrozumienia języka asemblera i skomplikowanego zrozumienia mechanizmów alokacji pamięci w systemie operacyjnym Linux, a także interpretacji danych przechowywanych na stosie i w rejestrach.
Uruchamianie programu w GDB
Alternatywnie, można również zdecydować się na uruchomienie GNU Debuggera, wpisując “gdb”, a następnie żądane argumenty wiersza poleceń, co następnie doprowadzi do wyświetlenia monitu o wpisanie konkretnego docelowego pliku binarnego, który wymaga debugowania. Po załadowaniu można przystąpić do wykonania programu, wpisując polecenie “run” lub po prostu używając skrótów klawiaturowych, takich jak “r”.
Aby program działał poprawnie, gdy wymaga argumentów wiersza poleceń, konieczne jest dołączenie ich do tytułu programu po wywołaniu.Strukturę gramatyczną stosowaną przez GNU Debugger (GDB) do ładowania i wykonywania aplikacji wraz z jej argumentami można przedstawić w następujący sposób:
gdb <program>
run <args>
Lub:
gdb
file <program>
run <args>
Ustawianie punktów przerwania za pomocą GDB
Punkty przerwania, które są celowymi przerwami w przepływie wykonywania podczas debugowania, służą jako z góry określone punkty zatrzymania w kodzie. Poprzez strategiczne umieszczenie tych znaczników, programiści mogą wstrzymać postęp swojego programu w określonych punktach i skrupulatnie przeanalizować wpływ zarówno na dane, jak i zmienne w miarę rozwoju każdej fazy.
Korzystając z GNU Debuggera (GDB) do debugowania aplikacji zawierającej symbole debugowania, można wybrać dwie metody ustawiania punktów przerwania. Obejmują one określenie punktu przerwania przy użyciu tytułu określonej funkcji lub wyznaczenie punktu przerwania na podstawie określonego numeru linii w kodzie. Odpowiednia składnia jest następująca:
break main
break 47
Aby uzyskać dostęp do pełnej listy punktów przerwania, które są aktualnie aktywne podczas tej sesji debugowania, należy wprowadzić następujące polecenie:
info breakpoints
Aby usunąć określone lub wszystkie bieżące punkty przerwania w kodzie, można użyć polecenia “delete " (w przypadku usuwania jednego) lub po prostu “delete” (aby wyeliminować je wszystkie).
delete 2
delete 3-5
GDB zapewnia możliwość ustanowienia warunkowych punktów przerwania, które wymagają spełnienia określonego warunku, aby program został wstrzymany podczas jego wykonywania. Warunek ten może obejmować zmiany wartości zmiennej, nieproduktywne wywołanie funkcji lub dowolne inne preferowane kryteria. Poniżej przedstawiono składnię stosowaną do wyznaczania warunkowych punktów przerwania:
break <location> if n == 2
Jeśli chcesz wznowić działanie programu po napotkaniu punktu przerwania, wprowadź polecenie “continue”.
continue
Przechodzenie przez kod
Badanie wykonywania programów komputerowych linia po linii jest niezbędne do zrozumienia ich działania na informacjach. Ostrożnie przechodząc przez wiele funkcji w oprogramowaniu i badając stan danych, można uzyskać głębszy wgląd w sposób, w jaki system realizuje zasady zakodowane w jego kodzie źródłowym.
Oprogramowanie umożliwia kompleksową analizę awarii systemu poprzez wskazanie ich źródła, zapewniając jednocześnie dogłębne badanie funkcjonowania programu poprzez precyzyjną kontrolę nad poszczególnymi liniami kodu. Proces sekwencyjnego wykonywania każdej linii jest osiągalny na trzy różne sposoby w ramach narzędzia debugowania znanego jako GDB.
Powyższa dyrektywa nakazuje debuggerowi GNU (GDB) przejście do kolejnych linii danego pliku źródłowego, umożliwiając w ten sposób kompleksowe przeglądanie bazy kodu na zasadzie indywidualnej.
Polecenie “next” w REPL Pycharm pozwala na wykonywanie kolejnych linii kodu w ramach aktualnie aktywnej funkcji, po czym wykonywanie zostaje przerwane. W przeciwieństwie do polecenia “step”, które działa na pojedynczych instrukcjach lub instrukcjach, “next” traktuje całą funkcję jako ciągły blok kodu, umożliwiając użytkownikom wykonywanie wielu linii bez przerywania.
Polecenie finish skutecznie kończy wykonywanie wszelkich zaległych bloków kodu, które pozostają w bieżącej funkcji, a następnie kończy procedurę.
Badanie zmiennych
Aby przeanalizować zmiany logiki programu poprzez badanie wartości zmiennych podczas wykonywania programu przy użyciu GDB, można wykorzystać następującą składnię do wyświetlania bieżącej wartości określonych zmiennych w środowisku debugowania:
print <variable>
Aby wyświetlić modyfikacje wartości określonej zmiennej przy każdej iteracji w pętli, można zastosować polecenie “display”. Takie podejście może być szczególnie korzystne do monitorowania i dokumentowania postępu wartości wspomnianej zmiennej podczas jej iteracyjnego procesu.
display <variable>
Ustawianie punktów obserwacyjnych
Punkty obserwacyjne i warunkowe punkty przerwania są ze sobą powiązane, ponieważ oba reagują na zmiany w programie. W szczególności punkty obserwacyjne służą do monitorowania modyfikacji danych występujących w kodzie źródłowym. Przykładowo, można zażyczyć sobie, by oprogramowanie wstrzymywało działanie, gdy zawartość określonej zmiennej ulegnie zmianie. Proces implementacji tej funkcjonalności przy użyciu GDB został szczegółowo opisany poniżej:
watch <variable_name>
Debugowanie specyficzne dla wątków za pomocą GDB
Wykorzystując debugger GDB, możliwe jest przeprowadzanie operacji debugowania na poszczególnych wątkach w aplikacjach wielowątkowych. Jako przykład ilustrujący, rozważmy zwięzły program C, który wykorzystuje wiele wątków do generowania drukowanych wiadomości.
Aby uzyskać informacje dotyczące aktywnych wątków w aplikacji, należy użyć polecenia “info”, po którym następuje pusty wiersz.
info threads
Aby uzyskać dostęp i interakcję z konkretnym wątkiem na liście, można użyć jego pozycji numerycznej lub indeksu w tablicy dostępnych opcji.Pozwala to na wybór i manipulowanie żądanym wątkiem w oparciu o jego przypisany identyfikator.
thread 2
Po wybraniu konkretnego wątku można stopniowo przechodzić przez jego sekwencję wykonywania, wykorzystując polecenia krokowe “step”, “next” i “finish”, jak pokazano wcześniej.
Zdalne debugowanie za pomocą GDB
Aby zdalnie debugować aplikacje, które są hostowane na innym urządzeniu, należy skonfigurować gdbserver na komputerze docelowym. Proces ten można wykonać za pomocą wstępnie zainstalowanego narzędzia do zarządzania pakietami w systemie operacyjnym lub przy użyciu dodatkowych menedżerów pakietów zainstalowanych w systemie.
Aby zainstalować gdbserver w systemie, który wykorzystuje Ubuntu lub Debiana jako podstawę, można w tym celu wykorzystać Advanced Package Tool (APT).
sudo apt install gdbserver
Po zakończeniu procesu instalacji należy przejść do katalogu zawierającego plik binarny i wykonać określone polecenie w tej lokalizacji, aby zainicjować działanie programu gdbserver.
gdbserver <ip>:<port> <binary>
Oczekuje się, że aplikacja “gdbserver” wyświetli komunikat wskazujący, że została uruchomiona i aktywnie nasłuchuje połączeń przychodzących na określonym porcie. Następnie na innym urządzeniu należy zainicjować instancję oprogramowania “GDB” i nawiązać połączenie z odległym serwerem, wykorzystując polecenie “target”, po którym następuje określone oznaczenie zamierzonego obiektu zapytania.
target remote <server_ip>:<port>
Pisanie skryptów GDB w celu automatyzacji debugowania
Wykorzystanie skryptów GDB umożliwia programistom wielokrotne wykonywanie wcześniej określonych poleceń GDB. W konsekwencji usprawnia to proces debugowania, eliminując potrzebę wykonywania powtarzających się zadań, takich jak ustawianie punktów przerwania, nawigowanie wykonywaniem kodu i drukowanie zmiennych danych. Wykorzystując te skrypty, programiści mogą zautomatyzować żmudną serię działań, zwiększając w ten sposób swoją produktywność podczas debugowania określonych fragmentów kodu.
Oto przykład:
set logging enabled on
set logging file sample.out
break main
command 1
backtrace
print N
continue
end
quit
W podanym fragmencie kodu instruuje się, że narzędzie do debugowania GDB powinno aktywować swoją funkcję rejestrowania i przechowywać wynikowy dziennik w pliku o nazwie “sample.out”. Dodatkowo, punkt przerwania jest wyznaczony w ramach podstawowej funkcji programu.
Aby wykonać punkt przerwania 1, który znajduje się na początku funkcji “main”, należy wykonać następujące kroki za pomocą debuggera GNU (GDB):Po pierwsze, zainicjuj śledzenie wsteczne, wprowadzając polecenie “backtrace”.Po drugie, wyświetl wartość zmiennej “N” za pomocą instrukcji “print N”. Po trzecie, kontynuuj wykonywanie programu, wpisując “continue”. Debugger początkowo przeprowadzi śledzenie wsteczne w celu określenia bieżącego stanu przepływu programu. Następnie wyświetli wartość zmiennej “N”. Następnie wznowi proces wykonywania. Wreszcie, po wyświetleniu wszystkich istotnych informacji, GDB z wdziękiem zakończy swoje działanie.
Aby wykonać ten skrypt, użyj:
gdb -x <script> <binary>
Teraz wiesz, jak debugować swoje programy za pomocą GDB!
Debugowanie jest krytyczną umiejętnością, a opanowanie wykorzystania GDB do celów debugowania znacznie zwiększa wszechstronność programisty. Różne funkcje zapewniane przez GDB, takie jak nawigacja krok po kroku przez kod, umieszczanie punktów przerwania, ukierunkowane debugowanie wątków i inne, czynią go potężnym narzędziem podczas badania plików binarnych w środowisku systemu operacyjnego Linux.
Dla tych, którzy chcą analizować i rozwiązywać problemy z programami w systemie operacyjnym Windows, warto rozważyć zgłębienie wiedzy na temat Windbg, natywnie zintegrowanego narzędzia do debugowania dla systemu Windows.