Position-independent executable
Explicando PIE e ASLR
Como vimos no tópico Endereçamento o processador calcula o endereço dos operandos na memória onde o resultado do cálculo será o endereço absoluto onde o operando está.
O problema disso √© que o c√≥digo que escrevemos precisa sempre ser carregado no mesmo endere√ßo sen√£o os endere√ßos nas instru√ß√Ķes estar√£o errados. Esse problema foi abordado no t√≥pico sobre MS-DOS, onde a diretiva org 0x100 precisa ser usada para que o NASM calcule o offset correto dos s√≠mbolos sen√£o os endere√ßos estar√£o errados e o programa n√£o funcionar√° corretamente.
Sistemas operacionais modernos têm um recurso de segurança chamado ASLR que dificulta a exploração de falhas de segurança no binário. Resumidamente ele carrega os endereços dos segmentos do executável em endereços aleatórios ao invés de sempre no mesmo endereço. Com o ASLR desligado os segmentos sempre são mapeados nos mesmos endereços.
Por√©m um c√≥digo que acessa endere√ßos absolutos jamais funcionaria apropriadamente com o ASLR ligado. √Č a√≠ que entra o conceito de Position-independent executable (PIE) que nada mais √© que um execut√°vel com c√≥digo que somente acessa endere√ßos relativos, ou seja, n√£o importa em qual endere√ßo (posi√ß√£o) voc√™ carregue o c√≥digo do execut√°vel ele ir√° funcionar corretamente.
Na nossa PoC eu instruí para compilar o programa usando a flag -no-pie no GCC para garantir que o linker não iria produzir um executável PIE já que ainda não havíamos aprendido sobre o assunto. Mas depois de aprender a escrever código com endereçamento relativo em Assembly fique à vontade para remover essa flag e começar a escrever programas independentes de posição.

PIE em x86-64

J√° vimos no t√≥pico Endere√ßamento que em x86-64 se tem um novo endere√ßamento relativo √† RIP. √Č muito mais simples escrever c√≥digo independente de posi√ß√£o no modo de 64-bit devido a isso.
Podemos usar a palavra-chave rel no endereçamento para dizer para o NASM que queremos que ele acesse um endereço relativo à RIP. Conforme exemplo:
mov rax, [rel my_var]
Também podemos usar a diretiva default rel para que o NASM compile todos os endereçamentos como relativos por padrão. Caso você defina o padrão como endereço relativo a palavra-chave abs pode ser usada da mesma maneira que a palavra-chave rel porém para definir o endereçamento como absoluto.
Um exemplo de PIE em modo de 64-bit:
main.c
assembly.asm
#include <stdio.h>
‚Äč
char *assembly(void);
‚Äč
int main(void)
{
printf("Resultado: %s\n", assembly());
return 0;
}
bits 64
default rel
‚Äč
section .rodata
msg: db "Hello World!", 0
‚Äč
section .text
‚Äč
global assembly
assembly:
lea rax, [msg]
ret
Experimente compilar sem a flag -no-pie para o GCC na hora de linkar:
$ nasm assembly.asm -o assembly.o -felf64
$ gcc main.c -c -o main.o
$ gcc *.o -o test
Deveria funcionar normalmente. Mas experimente comentar a diretiva default rel na linha 2 e compilar novamente, você vai obter um erro parecido com esse:
Repare que o erro foi emitido pelo linker (ld) e não pelo compilador em si. Acontece que como usamos um endereço absoluto o NASM colocou o endereço do símbolo msg na relocation table para ser resolvido pelo linker, onde o linker é quem definiria o endereço absoluto do mesmo.
Só que como removemos o -no-pie o linker tentou produzir um PIE e por isso emitiu um erro avisando que aquela referência para um endereço absoluto não pode ser usada.

PIE em IA-32

Como o endere√ßo relativo ao Instruction Pointer s√≥ existe em modo de 64-bit, nos outros modos de processamento n√£o √© nativamente poss√≠vel obter um endere√ßamento relativo. O compilador GCC resolve esse problema criando um pequeno procedimento cujo o √ļnico intuito √© obter o valor no topo da pilha e armazenar em um registrador. Conforme ilustra√ß√£o abaixo:
funcao:
call __x86.get_pc_thunk.bx
add ebx, 12345 ; Soma EBX com o endereço relativo 12345
; ...
‚Äč
__x86.get_pc_thunk.bx:
mov ebx, [esp]
ret
Ao chamar o procedimento __x86.get_pc_thunk.bx o endereço da instrução seguinte na memória é empilhado pela instrução CALL, portanto mov ebx, [esp] salva o endereço que EIP terá quando o procedimento retornar em EBX.
Quando a instrução add ebx, 12345 é executada o valor de EBX coincide com o endereço da própria instrução ADD.
Last modified 11mo ago
Export as PDF
Copy link
On this page
PIE em x86-64
PIE em IA-32