GDB executa o executável duas vezes
OK, essa não é a possibilidade mais prática em muitos casos, mas é educacional e satisfaz minha obsessão por ver as coisas realmente funcionando.
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
Para aquele com -pie
, vemos que o endereço de main
muda entre as execuções:
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>.
Neste exemplo, o endereço da primeira execução foi 0x55db0066b79a
e o segundo 0x563910ccd79a
.
Mas, para o com -no-pie
, o endereço de main
permanece o mesmo 0x400627
para as duas execuções:
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
garante que o ASLR esteja ativado (o padrão no Ubuntu 17.10): Como posso desativar temporariamente o ASLR (randomização de layout de espaço de endereço)? | Pergunte ao Ubuntu .
set disable-randomization off
é necessário caso contrário, o GDB, como o nome sugere, desativa o ASLR para o processo, por padrão, para fornecer endereços fixos em execuções para melhorar a experiência de depuração: Diferença entre endereços gdb e endereços" reais "? | Estouro de pilha
readelf
diversão
Além disso, também podemos observar que:
readelf -s ./nopie | grep main
fornece o endereço de carregamento real do tempo de execução:
69: 0000000000400627 370 FUNC GLOBAL DEFAULT 13 main
enquanto:
readelf -s ./pie | grep main
dá apenas um deslocamento:
70: 000000000000079a 401 FUNC GLOBAL DEFAULT 14 main
Ao desativar o ASLR (com randomize_va_space
ou set disable-randomization off
), o GDB sempre fornece main
o endereço: 0x5555555547a9
, então deduzimos que o endereço -pie
é composto de:
0x555555554000 + random offset + symbol offset (79a)
TODO onde está 0x555555554000 codificado no kernel do Linux / glibc loader / where?
Testado no Ubuntu 18.04.
Pergunta relacionada: