readelf-lWlnstatElffiletypeisDYN (Position-Independent Executablefile)Entrypoint0x1c00Thereare9programheaders,startingatoffset64ProgramHeaders:TypeOffsetVirtAddrPhysAddrFileSizMemSizFlgAlignPHDR0x0000400x00000000000000400x00000000000000400x0001f80x0001f8R0x8INTERP0x0002380x00000000000002380x00000000000002380x00001b0x00001bR0x1[Requesting program interpreter: /lib/ld-linux-aarch64.so.1]LOAD0x0000000x00000000000000000x00000000000000000x003f7c0x003f7cRE0x10000LOAD0x00fc480x000000000001fc480x000000000001fc480x0005280x001190RW0x10000DYNAMIC0x00fc580x000000000001fc580x000000000001fc580x0002000x000200RW0x8NOTE0x0002540x00000000000002540x00000000000002540x0000e00x0000e0R0x4GNU_EH_FRAME0x0036100x00000000000036100x00000000000036100x0001b40x0001b4R0x4GNU_STACK0x0000000x00000000000000000x00000000000000000x0000000x000000RW0x10GNU_RELRO0x00fc480x000000000001fc480x000000000001fc480x0003b80x0003b8R0x1SectiontoSegmentmapping:SegmentSections...0001.interp02.interp.note.gnu.build-id.note.ABI-tag.note.package.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.text.fini.rodata.eh_frame_hdr.eh_frame03.init_array.fini_array.dynamic.got.data.bss04.dynamic05.note.gnu.build-id.note.ABI-tag.note.package06.eh_frame_hdr0708.init_array.fini_array.dynamic.got
The previous program has 9 nagłówków programu, then, the mapowanie segmentów indicates in which program header (from 00 to 08) każda sekcja jest zlokalizowana.
PHDR - Nagłówek programu
Contains the program header tables and metadata itself.
INTERP
Indicates the path of the loader to use to load the binary into memory.
LOAD
These headers are used to indicate jak załadować binarny do pamięci.
Each LOAD header indicates a region of pamięci (size, permissions and alignment) and indicates the bytes of the ELF binarnego do skopiowania tam.
For example, the second one has a size of 0x1190, should be located at 0x1fc48 with permissions read and write and will be filled with 0x528 from the offset 0xfc48 (it doesn't fill all the reserved space). This memory will contain the sections .init_array .fini_array .dynamic .got .data .bss.
DYNAMIC
This header helps to link programs to their library dependencies and apply relocations. Check the .dynamic section.
NOTE
This stores vendor metadata information about the binary.
GNU_EH_FRAME
Defines the location of the stack unwind tables, used by debuggers and C++ exception handling-runtime functions.
GNU_STACK
Contains the configuration of the stack execution prevention defense. If enabled, the binary won't be able to execute code from the stack.
GNU_RELRO
Indicates the RELRO (Relocation Read-Only) configuration of the binary. This protection will mark as read-only certain sections of the memory (like the GOT or the init and fini tables) after the program has loaded and before it begins running.
In the previous example it's copying 0x3b8 bytes to 0x1fc48 as read-only affecting the sections .init_array .fini_array .dynamic .got .data .bss.
Note that RELRO can be partial or full, the partial version do not protect the section .plt.got, which is used for lazy binding and needs this memory space to have write permissions to write the address of the libraries the first time their location is searched.
TLS
Defines a table of TLS entries, which stores info about thread-local variables.
Nagłówki sekcji
Section headers gives a more detailed view of the ELF binary
It also indicates the location, offset, permissions but also the typ danych it section has.
Meta Sections
String table: Zawiera wszystkie ciągi potrzebne przez plik ELF (ale nie te, które są faktycznie używane przez program). Na przykład zawiera nazwy sekcji takie jak .text lub .data. A jeśli .text jest na offset 45 w tabeli ciągów, użyje liczby 45 w polu name.
Aby znaleźć, gdzie znajduje się tabela ciągów, ELF zawiera wskaźnik do tabeli ciągów.
Symbol table: Zawiera informacje o symbolach, takie jak nazwa (offset w tabeli ciągów), adres, rozmiar i więcej metadanych o symbolu.
Main Sections
.text: Instrukcja programu do uruchomienia.
.data: Zmienne globalne z określoną wartością w programie.
.bss: Zmienne globalne pozostawione niezainicjowane (lub zainicjowane do zera). Zmienne tutaj są automatycznie inicjowane do zera, co zapobiega dodawaniu niepotrzebnych zer do binarnego.
.rodata: Stałe zmienne globalne (sekcja tylko do odczytu).
.tdata i .tbss: Podobnie jak .data i .bss, gdy używane są zmienne lokalne dla wątków (__thread_local w C++ lub __thread w C).
.dynamic: Zobacz poniżej.
Symbols
Symbols to nazwane miejsce w programie, które może być funkcją, globalnym obiektem danych, zmiennymi lokalnymi dla wątków...
readelf -s lnstat
Symbol table '.dynsym' contains 49 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000001088 0 SECTION LOCAL DEFAULT 12 .init
2: 0000000000020000 0 SECTION LOCAL DEFAULT 23 .data
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strtok@GLIBC_2.17 (2)
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND s[...]@GLIBC_2.17 (2)
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strlen@GLIBC_2.17 (2)
6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND fputs@GLIBC_2.17 (2)
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND exit@GLIBC_2.17 (2)
8: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _[...]@GLIBC_2.34 (3)
9: 0000000000000000 0 FUNC GLOBAL DEFAULT UND perror@GLIBC_2.17 (2)
10: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterT[...]
11: 0000000000000000 0 FUNC WEAK DEFAULT UND _[...]@GLIBC_2.17 (2)
12: 0000000000000000 0 FUNC GLOBAL DEFAULT UND putc@GLIBC_2.17 (2)
[...]
Każdy wpis symbolu zawiera:
Nazwa
Atrybuty powiązania (słaby, lokalny lub globalny): Lokalny symbol może być dostępny tylko przez sam program, podczas gdy symbol globalny jest współdzielony poza programem. Słaby obiekt to na przykład funkcja, która może być nadpisana przez inną.
Typ: NOTYPE (typ nieokreślony), OBJECT (globalna zmienna danych), FUNC (funkcja), SECTION (sekcja), FILE (plik źródłowy dla debuggerów), TLS (zmienna lokalna dla wątku), GNU_IFUNC (funkcja pośrednia do relokacji)
Katalog NEEDED wskazuje, że program musi załadować wspomnianą bibliotekę, aby kontynuować. Katalog NEEDED jest uzupełniany, gdy wspólna biblioteka jest w pełni operacyjna i gotowa do użycia.
Relokacje
Loader musi również relokować zależności po ich załadowaniu. Te relokacje są wskazane w tabeli relokacji w formatach REL lub RELA, a liczba relokacji jest podana w sekcjach dynamicznych RELSZ lub RELASZ.
Jeśli program jest ładowany w innym miejscu niż preferowany adres (zwykle 0x400000), ponieważ adres jest już używany lub z powodu ASLR lub innego powodu, statyczna relokacja poprawia wskaźniki, które miały wartości oczekujące, że binarny plik zostanie załadowany w preferowanym adresie.
Na przykład każda sekcja typu R_AARCH64_RELATIV powinna mieć zmodyfikowany adres na podstawie przesunięcia relokacji plus wartość dodana.
Dynamiczne Relokacje i GOT
Relokacja może również odnosić się do zewnętrznego symbolu (jak funkcja z zależności). Na przykład funkcja malloc z libC. Wtedy, loader, ładowując libC w adresie, sprawdza, gdzie funkcja malloc jest załadowana, i zapisuje ten adres w tabeli GOT (Global Offset Table) (wskazanej w tabeli relokacji), gdzie powinien być określony adres malloc.
Tabela Łączenia Procedur
Sekcja PLT pozwala na leniwe wiązanie, co oznacza, że rozwiązywanie lokalizacji funkcji będzie wykonywane za pierwszym razem, gdy zostanie ona wywołana.
Więc gdy program wywołuje malloc, tak naprawdę wywołuje odpowiadającą lokalizację malloc w PLT (malloc@plt). Przy pierwszym wywołaniu rozwiązuje adres malloc i przechowuje go, więc następnym razem, gdy malloc jest wywoływane, ten adres jest używany zamiast kodu PLT.
Inicjalizacja Programu
Po załadowaniu programu nadszedł czas, aby go uruchomić. Jednak pierwszy kod, który jest uruchamiany, nie zawsze jest funkcją main. Dzieje się tak, ponieważ na przykład w C++, jeśli zmienna globalna jest obiektem klasy, ten obiekt musi być zainicjowanyprzed uruchomieniem main, jak w:
Zauważ, że te zmienne globalne znajdują się w .data lub .bss, ale w listach __CTOR_LIST__ i __DTOR_LIST__ obiekty do inicjalizacji i destrukcji są przechowywane w celu ich śledzenia.
Z kodu C można uzyskać ten sam wynik, używając rozszerzeń GNU:
__attributte__((constructor)) //Add a constructor to execute before__attributte__((destructor)) //Add to the destructor list
Z perspektywy kompilatora, aby wykonać te działania przed i po wykonaniu funkcji main, można stworzyć funkcję init i funkcję fini, które będą odniesione w sekcji dynamicznej jako INIT i FIN. i są umieszczone w sekcjach init i fini ELF.
Inną opcją, jak wspomniano, jest odniesienie do list __CTOR_LIST__ i __DTOR_LIST__ w wpisach INIT_ARRAY i FINI_ARRAY w sekcji dynamicznej, a długość tych list jest wskazywana przez INIT_ARRAYSZ i FINI_ARRAYSZ. Każdy wpis to wskaźnik do funkcji, która będzie wywoływana bez argumentów.
Ponadto, możliwe jest również posiadanie PREINIT_ARRAY z wskaźnikami, które będą wykonywane przed wskaźnikami INIT_ARRAY.
Kolejność inicjalizacji
Program jest ładowany do pamięci, statyczne zmienne globalne są inicjalizowane w .data a niezainicjowane są zerowane w .bss.
Wszystkie zależności dla programu lub bibliotek są inicjowane i wykonywane jest dynamiczne linkowanie.
Funkcje PREINIT_ARRAY są wykonywane.
Funkcje INIT_ARRAY są wykonywane.
Jeśli istnieje wpis INIT, jest wywoływany.
Jeśli jest to biblioteka, dlopen kończy się tutaj, jeśli program, nadszedł czas na wywołanie rzeczywistego punktu wejścia (funkcja main).
Pamięć lokalna dla wątków (TLS)
Są definiowane za pomocą słowa kluczowego __thread_local w C++ lub rozszerzenia GNU __thread.
Każdy wątek będzie utrzymywał unikalną lokalizację dla tej zmiennej, więc tylko wątek może uzyskać dostęp do swojej zmiennej.
Gdy to jest używane, sekcje .tdata i .tbss są używane w ELF. Które są podobne do .data (zainicjowane) i .bss (niezainicjowane), ale dla TLS.
Każda zmienna będzie miała wpis w nagłówku TLS określający rozmiar i offset TLS, który jest offsetem, którego użyje w lokalnym obszarze danych wątku.
__TLS_MODULE_BASE to symbol używany do odniesienia się do adresu bazowego pamięci lokalnej wątku i wskazuje na obszar w pamięci, który zawiera wszystkie dane lokalne wątku modułu.