> For the complete documentation index, see [llms.txt](https://www.ctfrecipes.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://www.ctfrecipes.com/pwn/protections/pie.md).

# PIE

**P**osition **I**ndependent **E**xecutable (**PIE**) is a feature that causes the file to be **loaded into a different memory address every time it is run**.

This means that hardcoding values, such as function addresses and gadget locations, is not possible without first determining their locations.

{% hint style="danger" %}
Add the parameter `-no-pie -fno-pie` using gcc in order to disable PIE when compiling the binary
{% endhint %}

## How it works ?

PIE executables are based on **relative** rather than **absolute** addresses, meaning that while the locations in memory are random the **offsets between different** **parts** of the binary remain **constant**.

{% hint style="info" %}
If the function `main` is located 0x42 bytes after the base address of the binary, this offset will always be the same on each runtime.

This means that if the address of the `main` function is leaked, it's possible to recover the base address of the binary by simply subtracting 0x42.
{% endhint %}

## Double-Checking

Due to the way PIE randomisation works, the base address of a PIE executable will **always** end in the hexadecimal characters `000`. This is because **pages** are the things being randomised in memory, which have a standard size of `0x1000`. Operating Systems keep track of page tables which point to each section of memory and define the permissions for each section, similar to segmentation.

{% hint style="info" %}
Checking the base address ends in `000` it's a good point to validate the leaked address.
{% endhint %}

## Bypassing PIE

It is possible to bypass PIE, by **finding a single address** and using it to **determine the location of the binary in memory**. One way to leak this address is through the [stack](/pwn/general-knowledge/operation-of-the-stack.md) !

The return pointer is often stored on the stack. By using a technique such as [format string](/pwn/stack-exploitation/format-string/data-leak.md) exploitation or some other method, it is possible to read the value of the return pointer off the stack.

Since the return pointer is a **static offset** away **from the base address of the binary**, it can be used to **calculate the location of the binary in memory**.
