Jaka jest opcja-fPIE dla plików wykonywalnych niezależnych od pozycji w gcc i ld?

Jak zmieni kod, np. wywołania funkcji?

 45

2 answers

PIE ma obsługiwać randomizację układu przestrzeni adresowej (ASLR) w plikach wykonywalnych.

Przed utworzeniem trybu PIE, plik wykonywalny programu nie mógł być umieszczony pod losowym adresem w pamięci, tylko biblioteki dynamiczne kodu niezależne od pozycji (pic) mogły zostać przeniesione do losowego offsetu. Działa bardzo podobnie do tego, co pic robi dla bibliotek dynamicznych, różnica polega na tym, że tabela połączeń procedur (PLT) nie jest tworzona, zamiast tego Relokacja względna jest używany.

Po włączeniu obsługi PIE w gcc / linkers, ciało programu jest kompilowane i linkowane jako kod niezależny od pozycji. Dynamiczny linker wykonuje pełne przetwarzanie relokacji w module programu, podobnie jak biblioteki dynamiczne. Każde użycie danych globalnych jest konwertowane na dostęp poprzez globalną tabelę offsetów (GOT) i dodawane są relokacje GOT.

PIE jest dobrze opisane w tej prezentacji OpenBSD PIE .

Zmiany w funkcjach są pokazane w tym slajdzie (PIE vs PIC).

X86 pic vs pie

Lokalne zmienne globalne i funkcje są optymalizowane w pie

Zewnętrzne zmienne globalne i funkcje są takie same jak pic

And in this slide (Pie vs old-style linking)

X86 pie vs no-flags (fixed)

Lokalne zmienne globalne i funkcje są podobne do stałych

Zewnętrzne zmienne globalne i funkcje są takie same jak pic

Uwaga, że ciasto może być niezgodny z -static

 55
Author: osgx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-09 03:20:03

Minimal runnable przykład: GDB the executable twice

Dla tych, którzy chcą zobaczyć jakąś akcję:

printf '
#include <stdio.h>
int main() {
    puts("hello world");
}
' > main.c
gcc -std=c99 -pie -fpie -ggdb3 -o pie main.c
gcc -std=c99 -no-pie -fno-pie -ggdb3 -o nopie main.c
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
gdb -batch -nh -ex 'set disable-randomization off' \
  -ex 'start' -ex 'info line' \
  -ex 'start' -ex 'info line' \
  ./pie
gdb -batch -nh -ex 'set disable-randomization off' \
  -ex 'start' -ex 'info line' \
  -ex 'start' -ex 'info line' \
  ./nopie

Dla tego z -pie, widzimy, że adres main zmienia się między runami:

Temporary breakpoint 1 at 0x7a9: file memory_layout.c, line 31.
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Temporary breakpoint 1, main (argc=1, argv=0x7ffe57d75318) at memory_layout.c:31
31      int main(int argc, char **argv) {
Line 31 of "memory_layout.c" starts at address 0x55db0066b79a <main> and ends at 0x55db0066b7a9 <main+15>.
Temporary breakpoint 2 at 0x55db0066b7a9: file memory_layout.c, line 31.
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Temporary breakpoint 2, main (argc=1, argv=0x7ffd03b67d68) at memory_layout.c:31
31      int main(int argc, char **argv) {
Line 31 of "memory_layout.c" starts at address 0x563910ccd79a <main> and ends at 0x563910ccd7a9 <main+15>.

Więc w tym przykładzie adres dla pierwszego uruchomienia to 0x55db0066b79a, a dla drugiego 0x563910ccd79a.

Ale dla tego z -no-pie, adres main pozostaje ten sam 0x400627 dla obu przebiegów:

Temporary breakpoint 1 at 0x400636: file ./memory_layout.c, line 28.

Temporary breakpoint 1, main (argc=1, argv=0x7ffd5f69c8b8) at ./memory_layout.c:28
warning: Source file is more recent than executable.
28      int bss = 0;
Line 28 of "./memory_layout.c" starts at address 0x400627 <main> and ends at 0x400636 <main+15>.
Temporary breakpoint 2 at 0x400636: file ./memory_layout.c, line 28.

Temporary breakpoint 2, main (argc=1, argv=0x7ffdd9f74bd8) at ./memory_layout.c:28
28      int bss = 0;
Line 28 of "./memory_layout.c" starts at address 0x400627 <main> and ends at 0x400636 <main+15>.

echo 2 | sudo tee /proc/sys/kernel/randomize_va_space zapewnia, że ASLR jest włączony (domyślnie w Ubuntu 17.10): Jak mogę tymczasowo wyłączyć ASLR (randomizację układu przestrzeni adresowej)? / Zapytaj Ubuntu .

set disable-randomization off czy w przeciwnym razie GDB, jak sama nazwa wskazuje, domyślnie wyłącza ASLR dla procesu, aby dać stałe adresy w różnych seriach, aby poprawić doświadczenie debugowania: różnica między adresami gdb i "prawdziwymi" adresami? / Stack Overflow

readelf fun

Ponadto możemy również zauważyć, że:

readelf -s ./nopie | grep main

Daje rzeczywisty adres ładowania runtime:

69: 0000000000400627   370 FUNC    GLOBAL DEFAULT   13 main

While:

readelf -s ./pie | grep main

Daje tylko przesunięcie:

70: 000000000000079a   401 FUNC    GLOBAL DEFAULT   14 main

Wyłączając ASLR (z randomize_va_space lub set disable-randomization off), GDB zawsze podaje main adres: 0x5555555547a9, więc wnioskujemy, że adres -pie składa się z:

0x555555554000 + random offset + symbol offset (79a)

TODO gdzie jest 0x555555554000 zakodowany na twardo w jądrze Linuksa / glibc loader / wherever? jak określa się adres sekcji tekstowej pliku wykonywalnego PIE w Linuksie?

Sprawdzone w Ubuntu 18.04.

Podobne pytanie: Jak mogę stwierdzić, z czymś takim jak objdump, czy plik obiektowy został zbudowany z-fPIC?

 3
Author: Ciro Santilli 新疆改造中心 六四事件 法轮功,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-14 21:42:55