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.
Następnie należy zaznaczyć projekt niewspółdzielony (ang. non-shared), ponieważ pracować nad nim będzie tylko jedna osoba.
Kolejny krok to wybranie katalogu na pliki oraz wpisanie nazwy projektu.
Teraz można uruchomić narzędzie do przeglądania kodu, czyli CodeBrowser.
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.
Importowanie pliku Weird.Win64.Blau!E4.exe
Plik binarny można zaimportować wybierając z górnego menu File / Import File.
W oknie wyboru należy przejść do odpowiedniego katalogu i wskazać plik binarny.
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.
W oknie dialogowym pytającym o przeprowadzenie analizy należy kliknąć Tak (ang. yes).
Można zostawić domyślnie zaznaczone rodzaje analizy.
Kolejne okno dialogowe zawiera podstawowe informacje o importowanym pliku.
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.
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).
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.
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.
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.
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).
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.
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.
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).
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.
Wnętrze funkcji nazwanej ExecuteRawBytes potwierdza próbę wykonania surowych bajtów jako kodu maszynowego.
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.
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.
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))
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);
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.
W oknie wyboru należy przejść do odpowiedniego katalogu i wskazać plik binarny Microbe.Win64.Blau!E4.clear.
Przy całkowicie surowych danych będzie potrzebne ręczne określenie architektury procesora dla importowanego kodu maszynowego.
Poniżej przedstawiono potwierdzenie parametrów wybranych dla surowego pliku binarnego.
Kolejne okno dialogowe zawiera podstawowe informacje o importowanym pliku.
Teraz można uruchomić narzędzie do przeglądania kodu, czyli CodeBrowser. Podobnie jak w przypadku poprzedniego pliku.
W oknie dialogowym pytającym o przeprowadzenie analizy należy kliknąć Tak (ang. yes).
Można zostawić domyślnie zaznaczone rodzaje analizy. Podobnie jak w przypadku poprzedniego pliku.
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).
▲ 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.
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.
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.
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.
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.