Inżynieria wsteczna, część 1 — analiza statyczna

Data: 05.11.2020, 10.11.2020

Narzędzia

Obsługa programu GHIDRA

  1. Tworzymy nowy projekt

  2. Importujemy program binarny (przycisk I)

  3. Otwieramy program binarny (podwójnym kliknięciem na plik w liście plików)

  4. Uruchamiamy automatyczną analizę (domyślne ustawienia powinny działać) i czekamy na zakończenie

  5. Przeglądamy kod, poprawiamy błędnie wywnioskowane informacje, dodajemy typy danych, nazywamy funkcje, …

Najważniejsze funkcje programu GHIDRA:

  • zmiana nazwy, parametrów i typu zwracanego funkcji: klikamy w nazwę funkcji w panelu disassemblera (pierwsze wystąpienie nazwy — drugie nie działa) i naciskamy F

  • zmiana typu zmiennej lokalnej: klikamy w nazwę zmiennej lokalnej w panelu dekompilacji, naciskamy Ctrl-L

  • zmiana nazwy zmiennej lokalnej: jak wyżej, naciskamy L

Przykład 1: proste porównanie

Program: simple

Zadanie: znaleźć poprawne hasło do programu.

Jest kilka sposobów rozwiązania zadania:

  1. Ładujemy do programu GHIDRA, czytamy funkcję main

  2. Używamy polecenia strings i po prostu znajdujemy hasło

Źródło: simple.c

Przykład 2: prosty szyfr

Program: encrypted

Zadanie: znaleźć poprawne hasło do programu.

  1. Ładujemy do programu GHIDRA

  2. Czytamy funkcję main, widzimy że właściwe sprawdzenie następuje znak po znaku w funkcji check

  3. Czytamy i odwracamy funkcję check

Źródło: encrypted.c

Przykład 3: obliczenia

Program: key_checker

Zadanie: znaleźć poprawne hasło do programu.

  1. Ładujemy do programu GHIDRA

  2. Program nie ma symboli — znajdujemy i oznaczamy funkcję main przez popatrzenie na punkt wejścia programu i wzięcie pierwszego parametru do __libc_start_main

  3. Zmieniamy nazwę zmiennej, do której scanf wczytuje hasło i poprawiamy jej typ na char[64] (GHIDRA nie radzie sobie z wykryciem rozmiaru sama)

  4. Widzimy wywołania do trzech podfunkcji — pierwsza jest oczywista, druga wymaga odrobiny ręcznej analizy

  5. W trzeciej podfunkcji widzimy, że wartość zwracana nie ma sensu — poprawiamy to, ustawiając typ zwracany na bool

  6. Pierwsze dwie funkcje odwracamy ręcznie, do odwrócenia trzeciej używamy np. Pythona 3 z bilbioteką gmpy2:

    import gmpy2
    print(int((gmpy2.invert(0x7b, 2**64) *  -0x34306269e095bb9a) % 2 ** 64).to_bytes(8, 'little'))
    

Przykład 4: struktury

Program: structures

Zadanie: znaleźć poprawne hasło do programu.