Dla początkujących bardzo frustrującą i uciążliwą częścią inżynierii odwrotnej jest brak jasnego pojęcia, co oznaczają różne parametry i wartości danych. Ten brak kontekstu w zakresie różnych ustawień wartości rejestrów, przesunięć pamięci, odwołań do wskaźników i argumentów funkcji można przezwyciężyć poprzez właściwe użycie typów danych. Jak być może już wiesz, środowisko wykonawcze architektur komputerów jest niezależne od typów danych, które są istotne dla twórcy oprogramowania w czasie programowania i są wykorzystywane przez kompilator do prawidłowego przypisywania alokacji pamięci, przesunięć elementów struktury, indeksów tablic i innych ustawień w czasie kompilacji. Jeśli porównamy oryginalny kod z domyślnym widokiem dekompilacji dla funkcji LoadStudents, pokazanym poniżej, funkcja dekompilacji może nie okazać się tak przydatna, jak to tylko możliwe. Będziemy kontynuować poprawę czytelności programu studentów poprzez przypisanie typów danych do wartości w funkcji main.
Kod źródłowy przedstawia pętlę for zwiększającą zmienną licznika o 1 w każdej iteracji, która jest używana jako indeks dla zmiennej globalnej studentów, która jest tablicą zdefiniowanego przez nas typu Student. Przed adnotacją zdekompilowana reprezentacja odpowiedniego kodu asemblera w języku C pokaże zmienną licznika indeksu pomnożoną przez 0x20 (co jest rozmiarem danych Ucznia). Ponadto, biorąc pod uwagę, że dekompilator nadal nie jest świadomy typów danych dla każdej zmiennej, każde odwołanie do wartości zostanie poddane rzutowaniu typu, co jeszcze bardziej komplikuje czytelność kodu źródłowego. Możemy łatwo poprawić czytelność, ustawiając zmienne z poprawnymi adnotacjami typu danych i zmieniając nazwy zmiennych. Załóżmy, że nie mamy kodu źródłowego, abyśmy mogli doświadczyć najczęstszego scenariusza, jakiego można się spodziewać podczas prawdziwej inżynierii odwrotnej. Wykonaj następujące kroki:
- Przejdź do funkcji LoadStudents, wyszukując ją w widoku drzewa symboli, a następnie przejdź do okna Dekompilacja, aby wprowadzić adnotacje. Zmienimy nazwy zmiennych, typy danych i sygnatury funkcji w oparciu o operacje i funkcje, z którymi są powiązane w kodzie.
- Bazując na sposobie wyłuskiwania zmiennej i ustawianiu jej z przesunięciem wynoszącym 32 (0x20) pomnożonym przez zmienną indeksującą liczbę, wiemy, że jest to tablica. Ustawione są niektóre wartości w pobliżu przesunięcia, jak pokazano poniżej:
- W linii 25. wartość całkowita jest dereferowana w odległości 24 (0x18) bajtów od przesunięcia (liczba * 32), więc można bezpiecznie założyć, że jest to wskaźnik do wartości całkowitej (int *). Nazwa powinna brzmieć „id”, ponieważ jest ustawiana ze zmiennej indeksowej licznika.
- W linii 26. funkcja strncpy kopiuje ciąg znaków odpowiadający nazwisku ucznia odczytanemu z pliku CSV do przesunięcia bazowego (liczba * 32), więc jest to tablica znaków o nieznanym rozmiarze. Możemy jednak zgadnąć, że są to 24 bajty, ponieważ to tam znajduje się przesunięcie poprzedniej wartości i nie powinno ono nadpisywać elementu własnej struktury (char [24]). Nazwiemy ten element struktury „imięm”.
- W linii 28. iVar1 jest ustawiany za pomocą funkcji atoi wywoływanej na podstawie wartości ocen w pliku CSV, która zwraca liczbę całkowitą, a następnie ustawiany jest z przesunięciem 0x1c od przesunięcia bazowego (liczba * 32). Załóżmy zatem, że jest to również liczba całkowita. Jest to członek „klasy” struktury ucznia.
- Teraz możemy zdefiniować własny typ danych struktury Studenta dla elementów tablicy studentów. Przejdź do okna Menedżer typów danych, kliknij prawym przyciskiem myszy typy danych programu „studenckiego”, wybierz podmenu Nowy i kliknij element „struktura”.
- Nazwij strukturę Student i ustaw jej rozmiar na 32 bajty.
- Przejdź do pierwszego wiersza w tabeli (offset 0), kliknij dwukrotnie DataType
pole i wpisz char[24]. Następnie kliknij dwukrotnie pole Nazwa i wpisz nazwę.
- W drugim wierszu (przesunięcie 24) ustaw pole DataType na int i ustaw pole Name na id.
- Powtórz to samo w trzecim wierszu (przesunięcie 28) i ustaw pole Nazwa na oceny.
- Jeśli okno Edytora struktury wygląda jak to na rysunku , kliknij ikonę Zapisz i zamknij okno. Konstrukcja jest już gotowa do użycia.
- Umieść kursor nad dowolną instancją zmiennej globalnej studentów i naciśnij CTRL-L, aby zmienić jej typ danych z niezdefiniowany[1024] na Student[32] (nasza struktura ma rozmiar 32, a 1024 podzielone przez 32 równa się 32) .
- Zmień pozostałe zmienne i funkcje w oparciu o ich kontekst. Na przykład zmienna local_20 jest ustawiana w wyniku funkcji fopen; dlatego powinien być ustawiony jako typ danych FILE *, a jego nazwa powinna wyglądać mniej więcej tak: fh.
- Naciśnij CTRL-L, aby zmienić jego typ na PLIK *.
- Wybierz nazwę zmiennej i naciśnij L lub kliknij prawym przyciskiem myszy i wybierz
Zmień nazwę zmiennej, aby zmienić nazwę zmiennej na fh.
C. Aby uniknąć rzutowania wywołania na fopen, kliknij funkcję prawym przyciskiem myszy, kliknij opcję Edytuj sygnaturę funkcji i, jeśli to konieczne, zmień sygnaturę funkcji, aby ustawić poprawny argument wywołania i zwrócić typy danych.
Jeśli nie masz pewności co do sygnatury standardowych funkcji, skorzystaj z podręcznika programisty, uruchamiając man 3 fopen w oknie terminala. Po zakończeniu tego procesu powinieneś zauważyć, że czytelność zarówno zdekompilowanego, jak i wyszczególniającego zdezasemblowany kod została znacznie poprawiona, jak pokazano poniżej. Ponadto każda inna funkcja odwołująca się do zmiennych, funkcji i typów danych z adnotacjami odniesie korzyści z tego wysiłku