Podstawy analizy plików binarnych za pomocą Ghidra

· Dawid Farbaniec

ethical.blue Magazine NaN. Anomalie i zniekształcenia

Podstawy analizy plików binarnych za pomocą Ghidra

Zastosowanie sztucznej inteligencji pozwala zazwyczaj uzyskać ogólny wgląd w naturę badanej anomalii. Nie dysponujemy jednak nieograniczonymi środkami finansowymi. Dodatkowo mocno zniekształcone programy i tak wymagają ręcznej analizy w celu dokładnego zbadania ich zachowania i wpływu na strefę ZONA. Z tego powodu przynajmniej podstawowa znajomość tradycyjnych narzędzi jest niezwykle istotna.

▲ Błękitna królowa
Sztuczna inteligencja Błękitna królowa (ang. Blue Queen)

Program Weird.Win64.Blau!E4.exe to klasyczny kod samomodyfikujący się dla architektury x64. Jego rdzeniem jest ładunek (ang. payload) o rozmiarze 301 bajtów, który przeszukuje wewnętrzne struktury procesu w celu znalezienia adresów funkcji Windows API. Kod maszynowy ładunku jest zniekształcony przez operację alternatywy wykluczającej (ang. eXclusive OR) z wartością 0Dh. Po dynamicznym uzyskaniu adresu funkcji MessageBoxA, wyświetlane jest okno dialogowe z napisem ethical.blue Magazine. Po zakończeniu działania, kod maszynowy jest wymazywany z pamięci operacyjnej.

Plik: Weird.Win64.Blau!E4.7z
Hasło: Weird.Win64.Blau!E4.ethical.blue

Tworzenie nowego projektu

W celu utworzenia nowego projektu należy wybrać z górnego menu File / New Project.

Rysunek 1. Tworzenie nowego projektu (Ghidra)

Następnie należy zaznaczyć projekt niewspółdzielony (ang. non-shared), ponieważ pracować nad nim będzie tylko jedna osoba.

Rysunek 2. Rodzaj projektu Non-Shared (Ghidra)

Kolejny krok to wybranie katalogu na pliki oraz wpisanie nazwy projektu.

Rysunek 3. Katalog i nazwa projektu (Ghidra)

Teraz można uruchomić narzędzie do przeglądania kodu, czyli CodeBrowser.

Rysunek 4. Uruchomienie narzędzia CodeBrowser (Ghidra)

Interfejs graficzny użytkownika narzędzia Ghidra

Okno dialogowe narzędzia CodeBrowser zaprezentowano poniżej.

W panelu Program Trees będą wyświetlone sekcje pliku binarnego zależnie od formatu (np. PE, ELF).

W Symbol Tree pojawią się funkcje importowane z bibliotek .dll, funkcje eksportowane przez program (np. entry), funkcje rozpoznane przez moduł dekompilatora i inne.

Menedżer typów danych (ang. Data Type Manager) pozwala określać jakie rodzaju są wskazane dane.

Okno Listing będzie zawierać widok kodu w języku Asembler, który udało się uzyskać z analizowanego pliku.

Natomiast okno Decompile pozwoli czytać fragmenty kodu w języku Asembler przekształcone do języka wyższego poziomu abstrakcji, którego składnia przypomina język C.

Komunikaty o błędach i informacje ze skryptów będą wyświetlane w oknie Console - Scripting.

Rysunek 5. Okno dialogowe narzędzia CodeBrowser (Ghidra)

Importowanie pliku Weird.Win64.Blau!E4.exe

Plik binarny można zaimportować wybierając z górnego menu File / Import File.

Rysunek 6. Import pliku binarnego do analizy (Ghidra)

W oknie wyboru należy przejść do odpowiedniego katalogu i wskazać plik binarny.

Rysunek 7. Import pliku Weird.Win64.Blau!E4.exe (Ghidra)

Narzędzie Ghidra rozpoznało format pliku oraz wybrało odpowiedni język Asemblera.

Wybrane dziwo (ang. weird) to plik w formacie Portable Executable. [5]

Kod maszynowy w pliku będzie traktowany jak rozkazy procesorów o architekturze x86 (64-bit) z kolejnością bajtów LE dla systemów Microsoft Windows.

Rysunek 8. Rozpoznany format pliku oraz język Asemblera (Ghidra)

W oknie dialogowym pytającym o przeprowadzenie analizy należy kliknąć Tak (ang. yes).

Rysunek 9. Okno dialogowe pytające o przeprowadzenie analizy (Ghidra)

Można zostawić domyślnie zaznaczone rodzaje analizy.

Rysunek 10. Okno dialogowe pytające o rodzaje analizy (Ghidra)

Kolejne okno dialogowe zawiera podstawowe informacje o importowanym pliku.

Rysunek 11. Podstawowe informacje o importowanym pliku (Ghidra)

Nagłówki i sekcje pliku PE

W panelu Program Trees okna narzędzia CodeBrowser można zobaczyć nagłówki i sekcje wczytanego pliku.

Zgodnie z dokumentem [5] opisującym format PE znaczenie poszczególnych sekcji jest następujące:

  • .text — zawiera kod maszynowy programu, czyli rozkazy procesora w postaci binarnej.
  • .rdata — dane tylko do odczytu z określoną wartością początkową (zainicjalizowane).
  • .data — dane z określoną wartością początkową (zainicjalizowane).
  • .rsrc — zawiera zasoby takie jak ikony, grafiki, pliki manifest i inne.
  • .reloc — odpowiada za dostosowanie adresów pamięci zawartych w pliku PE. Jej obecność jest związana z mechanizmem ASLR.

Poniżej przedstawiono zachowane informacje debugowania utworzone prawdopodobnie przez środowisko Microsoft Visual Studio i sugerujące, że pliki projektu były w katalogu C:\n\Anomaly. Artefakty tego typu mogą mieć znaczenie, ponieważ czasami zawierają nazwę użytkownika komputera lub inne dane sugerujące pochodzenie pliku anomalii.

Rysunek 12. Zachowane informacje o debugowaniu (Ghidra)

Po dwukrotnym kliknięciu na nazwę sekcji .data można zobaczyć przykładowy ciąg tekstowy ethical.blue znajdujący się w programie. Poszczególne kolumny to adres wirtualny (VA), dane w postaci ciągu bajtów w systemie heksadecymalnym, ich rodzaj (ds) oraz te same dane, ale w formie ciągu tekstowego ("ethical.blue"").

Po umieszczeniu kursora myszy nad określoną zmienną pojawia się kontrolka podpowiedzi (ang. tooltip) wyświetlająca różne rodzaje przesunięć (ang. offset).

Rysunek 13. Przykładowy ciąg tekstowy w sekcji .data (Ghidra)

Dla przykładowego ciągu tekstowego ethical.blue w badanym pliku PE poszczególne przesunięcia prezentują się następująco:

  • Imagebase Offset — miejsce w pamięci po załadowaniu programu. Po uruchomieniu program otrzymuje własną przestrzeń adresową i ciąg tekstowy ethical.blue znajdzie się pod adresem przesuniętym o +3004h od adresu bazowego programu (jest to tzw. RVA).
  • Memory Block Offset — przesunięcie względem początku konkretnej sekcji w pliku PE. Ciąg tekstowy ethical.blue będzie pod przesunięciem +4h bajty licząc od początku sekcji .data.
  • Byte Source Offset — przesunięcie względem początku pliku na dysku. Pozwala to powiązać określone miejsce z analizy w narzędziu Ghidra z przesunięciem w edytorze heksadecymalnym, w którym otworzono badany plik.

Znajomość rodzajów przesunięć (ang. offset) ma znaczenie przy uzyskiwaniu dostępu do miejsc w pliku z poziomu innych narzędzi niż Ghidra.

Możliwość modyfikacji danych w pliku binarnym

Poniżej przedstawiono możliwość modyfikacji danych w pliku binarnym za pomocą narzędzia Ghidra.

Rysunek 14. Możliwość modyfikacji danych w pliku binarnym (Ghidra)

Drzewo symboli (ang. Symbol Tree)

Warto przyjrzeć się również miejscu nazwanym Symbol Tree. W przypadku pliku badanego w tym artykule można zauważyć, że importowane są funkcje z biblioteki systemowej kernel32.dll. Eksportowane funkcje to punkt startowy (ang. entry). A zidentyfikowane automatycznie funkcje w programie to entry oraz FUN_140001000. Nazwa funkcji FUN_140001000 oznacza, że jej adres względny (RVA) to przesunięcie +1000h od adresu bazowego.

Rysunek 15. Drzewo symboli (Ghidra)

Schemat wywołań funkcji (ang. Function Call Graph)

W celu eksploracji dużej części dostępnej funkcjonalności warto z górnego menu wybrać pozycję Window i poeksperymentować z poszczególnymi oknami narzędzi.

Rysunek 16. Wyświetlenie okna ze schematem wywołań funkcji (Ghidra)

Schemat wywołań funkcji (ang. Function Call Graph) to jedno z podstawowych okien narzędziowych. Pozwala przejrzeć powiązania między funkcjami w formie grafu. Przykład poniżej prezentuje funkcję Windows API o nazwie VirtualProtect. Może to sugerować zmianę przez program uprawnień dostępu do określonego miejsca pamięci w przestrzeni adresowej. Dodatkowo funkcja FlushInstructionCache wskazuje na możliwość modyfikacji własnego kodu przez program. Dokładniejszego zbadania może wymagać funkcja FUN_140001000 (domyślna nazwa nadana przez Ghidra).

Rysunek 17. Schemat wywołań funkcji (Ghidra)

Dekompilator (ang. Decompiler)

Kolejne okno narzędziowe, które warto opisać to Decompiler. Jeśli nie jest domyślnie widoczne, należy wybrać z górnego menu pozycję Window / Decompiler.

Rysunek 18. Wyświetlenie okna z dekompilatorem (Ghidra)

Kod funkcji głównej analizowanego pliku w składni podobnej do języka C można zobaczyć poniżej. Warto dodać, że okno dekompilatora jest sychronizowane z oknem zawierającym kod w języku Asembler. Pozwala to łatwo przemieszczać się po różnych miejscach w programie.

Rysunek 19. Kod funkcji głównej analizowanego pliku w składni podobnej do języka C (Ghidra)

Nazwy funkcji i zmiennych można łatwo dostosować ręcznie lub za pomocą sztucznej inteligencji (po odpowiedniej integracji narzędzi). Dodatkowo Ghidra nie zawsze poprawnie rozpoznaje elementy badanego pliku. W takich sytuacjach można ręcznie zmienić typ określonych danych albo ustawić traktowanie danych jako kodu maszynowego (i na odwrót).

Rysunek 20. Możliwość zmiany nazw poszczególnych funkcji i zmiennych (Ghidra)

Poniżej zaprezentowano przykładowy kod po zmianie nazw funkcji i zmiennych na bardziej opisowe. Najpierw funkcja VirtualProtect ustawia prawa dostępu do obszaru pamięci na wartość PAGE_EXECUTE_READWRITE (0x40). Dalej surowe bajty są przywracane do czystej postaci za pomocą operacji alternatywy wykluczającej (ang. XOR) z wartością 0x0D (0Dh). Za wykonanie ładunku (ang. payload) odpowiada funkcja nazwana ExecuteRawBytes. Po zakończeniu działania, kod maszynowy jest wymazywany z pamięci operacyjnej.

Rysunek 21. Kod programu po zmianie nazw funkcji i zmiennych (Ghidra)

Wnętrze funkcji nazwanej ExecuteRawBytes potwierdza próbę wykonania surowych bajtów jako kodu maszynowego.

Rysunek 22. Funkcja wywołująca surowe bajty jako kod maszynowy (Ghidra)
Rysunek 23. Podgląd ciągu bajtów wywoływanych jako kod maszynowy (Ghidra)

Wyodrębnienie ciągu bajtów z kodem maszynowym

Początek przenoszonego ładunku (ang. payload) znajduje się pod przesunięciem (ang. offset) o wartości 0x4B3 (4B3h) względem początku pliku PE na dysku.

Rysunek 24. Przesunięcie (ang. offset) ciągu bajtów względem różnych miejsc (Ghidra)

Zakres bajtów od 0x4B3 do 0x5DF (włącznie, czyli tak na prawdę do 0x5E0) tworzy ładunek (ang. payload) o rozmiarze 0x12D, czyli można stwierdzić, że przenoszony fragment kodu maszynowego ma rozmiar 301 bajtów.

Rysunek 25. Przesunięcie (ang. offset) początku oraz końca ciągu bajtów (Ghidra)

Fragment kodu maszynowego można wyodrębnić na różne sposoby. W systemie Kali Linux można zastosować np. polecenie dd przedstawione poniżej.

dd if='Weird.Win64.Blau!E4.exe' of='Microbe.Win64.Blau!E4.dump' bs=1 skip=$((0x4B3)) count=$((0x12D))

Rysunek 26. Wyodrębnienie ciągu bajtów z kodem maszynowym (dd)

Wyodrębniony kod maszynowy można przywrócić do czystej postaci np. poniższym skryptem w języku PowerShell.

$a = "Microbe.Win64.Blau!E4.dump";
$b = "Microbe.Win64.Blau!E4.clear";
$k = 0x0D;
$f = [System.IO.File]::ReadAllBytes($a);
for ($i = 0; $i -lt $f.Length; $i++) {
$f[$i] = $f[$i] -bxor $k;
};
[System.IO.File]::WriteAllBytes($b, $f);

Rysunek 27. Operacja alternatywy wykluczającej ciągu bajtów z wartością 0Dh (PowerShell)

Importowanie pliku Microbe.Win64.Blau!E4

Plik binarny Microbe.Win64.Blau!E4.clear można zaimportować wybierając z górnego menu File / Import File.

Rysunek 28. Import pliku binarnego do analizy (Ghidra)

W oknie wyboru należy przejść do odpowiedniego katalogu i wskazać plik binarny Microbe.Win64.Blau!E4.clear.

Rysunek 29. Import pliku Microbe.Win64.Blau!E4.clear (Ghidra)

Przy całkowicie surowych danych będzie potrzebne ręczne określenie architektury procesora dla importowanego kodu maszynowego.

Rysunek 30. Określenie rodzaju języka Asembler dla importowanego programu (Ghidra)

Poniżej przedstawiono potwierdzenie parametrów wybranych dla surowego pliku binarnego.

Rysunek 31. Importowany plik z wybranym rodzajem języka Asembler (Ghidra)

Kolejne okno dialogowe zawiera podstawowe informacje o importowanym pliku.

Rysunek 32. Podstawowe informacje o importowanym pliku (Ghidra)

Teraz można uruchomić narzędzie do przeglądania kodu, czyli CodeBrowser. Podobnie jak w przypadku poprzedniego pliku.

Rysunek 33. Otworzenie pliku Microbe.Win64.Blau!E4.clear w narzędziu CodeBrowser (Ghidra)

W oknie dialogowym pytającym o przeprowadzenie analizy należy kliknąć Tak (ang. yes).

Rysunek 34. Okno dialogowe pytające o przeprowadzenie analizy (Ghidra)

Można zostawić domyślnie zaznaczone rodzaje analizy. Podobnie jak w przypadku poprzedniego pliku.

Rysunek 35. Okno dialogowe pytające o rodzaje analizy (Ghidra)

Dezasemblacja kodu maszynowego z pliku Microbe.Win64.Blau!E4

Narzędzie Ghidra domyślnie przedstawiło fragment kodu maszynowego jako ciąg bajtów. Wymagane jest wykonanie dezasemblacji, czyli odtworzenia rozkazów procesora x64 w postaci mnemoników z formy binarnej zawierającej kody operacyjne (ang. opcode).

Rysunek 36. Dezasemblacja kodu maszynowego (Ghidra)

▲ Błękitna królowa
Sztuczna inteligencja Błękitna królowa (ang. Blue Queen)

Program Microbe.Win64.Blau!E4 jest kodem o rozmiarze 301 bajtów, niezależnym od miejsca w pamięci. Przeszukuje on wewnętrzne struktury procesu w celu znalezienia adresów funkcji Windows API. Po dynamicznym uzyskaniu adresu funkcji MessageBoxA, wyświetlane jest okno dialogowe z napisem ethical.blue Magazine.

Fragment kodu programu Microbe.Win64.Blau!E4 uzyskanego przez dezasemblację przedstawiono poniżej.

Rysunek 37. Instrukcje sugerujące przemierzanie wewnętrznych struktur procesu (Ghidra)

Szczegółowe działanie instrukcji procesorów opartych na architekturze x64 można sprawdzić, korzystając z następujących dokumentów:

  • AMD64 Architecture Programmer's Manual
  • The Intel 64 and IA-32 Architectures Software Developer's Manual

Poniżej przedstawiono przykładowy fragment dokumentacji.

Rysunek 38. AMD64 Architecture Programmer's Manual

Warto dodać, że na końcu kodu maszynowego znajdują się przedstawione poniżej ciągi tekstowe. Zawierają one nazwę biblioteki systemowej user32.dll, nazwy wywoływanych funkcji Windows API oraz napis ethical.blue Magazine wyświetlany w oknie komunikatu.

Rysunek 39. Ciągi tekstowe odnalezione w pliku binarnym (Ghidra)

Uruchomienie pliku Weird.Win64.Blau!E4.exe

Plik Weird.Win64.Blau!E4.exe to klasyczne dziwo (ang. weird) ze strefy ZONA. Kod programu wygląda jak anomalia, ale nie wykazuje żadnego znaczącego wpływu na system operacyjny.

Rysunek 40. Uruchomienie pliku Weird.Win64.Blau!E4.exe

Wykaz literatury

[1] Advanced Micro Devices, Inc. (AMD), AMD64 Architecture Programmer's Manual, 2024.
[2] Advanced Micro Devices, Inc. (AMD), System V Application Binary Interface, 2025.
[3] Arm Limited, ELF for the Arm 64-bit Architecture (AArch64), 2025.
[4] Intel Corporation, The Intel 64 and IA-32 Architectures Software Developer's Manual, 2025.
[5] Microsoft Corporation, Microsoft Portable Executable and Common Object File Format Specification, 2025.