Friday, February 21, 2025

PIE

Address space layout randomization, aka ASLR -- and position independent executables (PIE), are used to improve the security of modern operating systems by making memory addresses less predictable.

Position-independent executables utilize address space layout randomization and have their base entry function shifted at runtime. We can see this by comparing the entry point address at runtime with the base address seen via readelf.

$ readelf -h /usr/bin/ls
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Position-Independent Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x6d30
  Start of program headers:          64 (bytes into file)
  Start of section headers:          140328 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         13
  Size of section headers:           64 (bytes)
  Number of section headers:         31
  Section header string table index: 30

On a system with PIE enabled binaries, the entry point _start will be modified because it gets computed in addition with another value. Runtime addresses essentially get calculated like:

Runtime Address = Base Address + Entry Point Offset

We can visualize this with a simple C program that prints the address of its main function. PIE will also shift all of the other functions addresses.

#include <stdio.h>

int main() {
    // Print the address of the main function 
    printf("Address of main: %p\n", main);
    return 0;
}
gcc -o entry entry.c
hexagr@vr:~$ ./entry 
Address of main: 0x62498320c149
hexagr@vr:~$ ./entry 
Address of main: 0x61bcab5a7149
hexagr@vr:~$ ./entry 
Address of main: 0x587688ff8149

PIC

If we force the additional use of the fPIC flag, we can make gcc to generate position-independent code (assembly) which (if not optimized away) might use the Global Offset Table.

hexagr@vr:~$ gcc -fPIC -S main.c -o main_fpic.s
hexagr@vr:~$ gcc -S main.c -o main_not_fpic.s
hexagr@vr:~$ diff main_fpic.s main_not_fpic.s 
18c18
< 	movq	main@GOTPCREL(%rip), %rax
---
> 	leaq	main(%rip), %rax

No comments:

Post a Comment