Jaka jest opcja-fPIE dla plików wykonywalnych niezależnych od pozycji w gcc i ld?
Jak zmieni kod, np. wywołania funkcji?
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
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?
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