Da li radite u kompaniji za kibernetičku bezbednost? Želite li da vidite svoju kompaniju reklamiranu na HackTricks? ili želite pristup najnovijoj verziji PEASS-a ili preuzimanje HackTricks-a u PDF formatu? Proverite PLANOVE ZA PRIJAVU!
Prethodni program ima 9 programskih zaglavlja, zatim, mapiranje segmenata pokazuje u kojem programskom zaglavlju (od 00 do 08) se svaki odeljak nalazi.
PHDR - Program HeaDeR
Sadrži tabele programskih zaglavlja i same metapodatke.
INTERP
Pokazuje putanju loadera koji se koristi za učitavanje binarnog fajla u memoriju.
LOAD
Ova zaglavlja se koriste da pokažu kako učitati binarni fajl u memoriju.
Svako LOAD zaglavlje pokazuje region memorije (veličinu, dozvole i poravnanje) i pokazuje bajtove ELF binarnog fajla koji treba kopirati tamo.
Na primer, drugo ima veličinu 0x1190, treba da se nalazi na 0x1fc48 sa dozvolama za čitanje i pisanje i biće popunjeno sa 0x528 od offseta 0xfc48 (ne popunjava sav rezervisani prostor). Ova memorija će sadržati odeljke .init_array .fini_array .dynamic .got .data .bss.
DYNAMIC
Ovo zaglavlje pomaže da se programi povežu sa njihovim zavisnostima biblioteka i primene relokacije. Proverite odeljak .dynamic.
NOTE
Čuva informacije o proizvođaču vezane za binarni fajl.
GNU_EH_FRAME
Definiše lokaciju tabela za odmotavanje steka, koje koriste debageri i funkcije za rukovanje izuzecima u C++-u.
GNU_STACK
Sadrži konfiguraciju odbrane od izvršavanja steka. Ako je omogućeno, binarni fajl neće moći da izvršava kod sa steka.
GNU_RELRO
Pokazuje konfiguraciju RELRO (Relocation Read-Only) binarnog fajla. Ova zaštita će označiti određene odeljke memorije kao samo za čitanje (kao što su GOT ili init i fini tabele) nakon što se program učita i pre nego što počne sa izvršavanjem.
U prethodnom primeru kopira 0x3b8 bajtova na 0x1fc48 kao samo za čitanje, utičući na odeljke .init_array .fini_array .dynamic .got .data .bss.
Imajte na umu da RELRO može biti delimičan ili potpun, delimična verzija ne štiti odeljak .plt.got, koji se koristi za leno povezivanje i zahteva da ovaj prostor u memoriji ima dozvole za pisanje kako bi upisao adresu biblioteka prvi put kada se njihova lokacija traži.
TLS
Definiše tabelu unosa TLS-a, koja čuva informacije o promenljivima lokalnim za nit.
Zaglavlja Odeljaka
Zaglavlja odeljaka pružaju detaljniji prikaz ELF binarnog fajla.
Tabela stringova: Sadrži sve stringove potrebne za ELF fajl (ali ne one koje zaista koristi program). Na primer, sadrži imena sekcija poput .text ili .data. Ako je .text na offsetu 45 u tabeli stringova, koristiće broj 45 u polju ime.
Da bi se pronašla lokacija tabele stringova, ELF sadrži pokazivač na tabelu stringova.
Tabela simbola: Sadrži informacije o simbolima poput imena (offset u tabeli stringova), adrese, veličine i dodatne metapodatke o simbolu.
Glavne Sekcije
.text: Instrukcije programa koje se izvršavaju.
.data: Globalne promenljive sa definisanom vrednošću u programu.
.bss: Globalne promenljive ostavljene neinicijalizovane (ili inicijalizovane na nulu). Promenljive ovde automatski se inicijalizuju na nulu, čime se sprečava dodavanje beskorisnih nula u binarni fajl.
.rodata: Konstantne globalne promenljive (sekcija samo za čitanje).
.tdata i .tbss: Slično kao .data i .bss kada se koriste promenljive lokalne za nit (__thread_local u C++ ili __thread u C).
.dynamic: Pogledajte ispod.
Simboli
Simboli su imenovane lokacije u programu koje mogu biti funkcija, globalni podaci, promenljive lokalne za nit...
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)
[...]
Dinamička sekcija
Svaki unos simbola sadrži:
Ime
Atributi vezivanja (slab, lokalni ili globalni): Lokalni simbol može pristupiti samo program sam, dok su globalni simboli deljeni izvan programa. Slab objekat je na primer funkcija koja može biti zamenjena drugom.
Tip: NOTYPE (nije naveden tip), OBJECT (globalna podatkovna promenljiva), FUNC (funkcija), SECTION (sekcija), FILE (izvorni kod datoteke za debager), TLS (promenljiva lokalna za nit), GNU_IFUNC (indirektna funkcija za premeštanje)
Direktorijum NEEDED ukazuje da programu treba da učita pomenutu biblioteku kako bi nastavio sa radom. Direktorijum NEEDED se završava kada je deljena biblioteka potpuno operativna i spremna za upotrebu.
Relokacije
Loader takođe mora da relokira zavisnosti nakon što ih učita. Ove relokacije su naznačene u tabeli relokacija u formatima REL ili RELA, a broj relokacija je dat u dinamičkim sekcijama RELSZ ili RELASZ.
Ako je program učitan na drugo mesto od preferiranog adrese (obično 0x400000) zbog toga što je adresa već zauzeta ili zbog ASLR-a ili bilo kog drugog razloga, statička relokacija ispravlja pokazivače koji su imali vrednosti očekujući da će se binarni fajl učitati na preferiranu adresu.
Na primer, bilo koji odeljak tipa R_AARCH64_RELATIV trebalo bi da izmeni adresu na relokacionom biasu plus vrednost addenda.
Dinamičke relokacije i GOT
Relokacija takođe može da se odnosi na spoljni simbol (kao što je funkcija iz zavisnosti). Na primer, funkcija malloc iz libC. Zatim, loader prilikom učitavanja libC na adresu proverava gde je učitana funkcija malloc, zatim će upisati ovu adresu u tabelu GOT (Global Offset Table) (naznačeno u tabeli relokacija) gde bi trebalo da bude navedena adresa malloc funkcije.
Tabela vezivanja procedura
Odeljak PLT omogućava lenje vezivanje, što znači da će se rešavanje lokacije funkcije obaviti prvi put kada se pristupi.
Dakle, kada program pozove malloc, zapravo poziva odgovarajuću lokaciju malloc u PLT-u (malloc@plt). Prvi put kada se pozove, rešava se adresa malloc i čuva se tako da se sledeći put kada se pozove malloc, umesto koda PLT-a koristi ta adresa.
Inicijalizacija programa
Nakon što je program učitan, vreme je da se pokrene. Međutim, prvi kod koji se pokreće nije uvek funkcija main. To je zato što na primer u C++-u, ako je globalna promenljiva objekat klase, ovaj objekat mora biti **inicijalizovan ** pre pokretanja funkcije main, kao u:
Napomena da se ove globalne promenljive nalaze u .data ili .bss, ali u listama __CTOR_LIST__ i __DTOR_LIST__ objekti za inicijalizaciju i destrukciju se čuvaju redosledom radi praćenja njih.
Iz C koda je moguće postići isti rezultat koristeći GNU ekstenzije:
__attributte__((constructor)) //Add a constructor to execute before__attributte__((destructor)) //Add to the destructor list
Iz perspektive kompajlera, moguće je izvršiti ove akcije pre i posle izvršavanja main funkcije kreiranjem init funkcije i fini funkcije koje će biti referisane u dinamičkoj sekciji kao INIT i FIN i smeštene u init i fini sekcije ELF-a.
Druga opcija je da se referišu liste __CTOR_LIST__ i __DTOR_LIST__** u unosima **INIT_ARRAY** i **FINI_ARRAY** u dinamičkoj sekciji, a dužina ovih lista je naznačena sa **INIT_ARRAYSZ** i **FINI_ARRAYSZ`. Svaki unos je pokazivač na funkciju koja će biti pozvana bez argumenata.
Takođe, moguće je imati PREINIT_ARRAY sa pokazivačima koji će biti izvršeni pre pokazivača iz INIT_ARRAY.
Redosled inicijalizacije
Program se učitava u memoriju, statičke globalne promenljive se inicijalizuju u .data sekciji, a neinicijalizovane se postavljaju na nulu u .bss sekciji.
Sve zavisnosti programa ili biblioteka se inicijalizuju i izvršava se dinamičko povezivanje.
Izvršavaju se funkcije PREINIT_ARRAY.
Izvršavaju se funkcije INIT_ARRAY.
Ako postoji unos INIT, on se poziva.
Ako je u pitanju biblioteka, dlopen se završava ovde, ako je program, vreme je da se pozove prava tačka ulaska (main funkcija).
Lokalno skladištenje niti (TLS)
Definišu se korišćenjem ključne reči __thread_local u C++-u ili GNU ekstenzijom __thread.
Svaka nit će održavati jedinstvenu lokaciju za ovu promenljivu tako da samo ta nit može pristupiti svojoj promenljivoj.
Kada se ovo koristi, sekcije .tdata i .tbss se koriste u ELF-u. One su poput .data (inicijalizovane) i .bss (neinicijalizovane) ali za TLS.
Svaka promenljiva će imati unos u zaglavlju TLS-a koji specificira veličinu i TLS offset, što je offset koji će koristiti u oblasti podataka lokalnih niti.
__TLS_MODULE_BASE je simbol koji se koristi za referisanje na baznu adresu lokalnog skladištenja niti i pokazuje na oblast u memoriji koja sadrži sve podatke lokalnih niti modula.