ELF
What is an ELF?
ELFs are the executable files of the Linux world. ELF stands for Executable and Linkable Format.
If you are new to this, you are probably more familiar with Windows .exe files, they serve the exact same purpose,
just for two different operating systems.
In this section, we will dive deeper into what an ELF file can reveal through static analysis,
using industry-standard tools like IDA.
ELF sections
The data contained in an ELF is divided among multiple sections, each one serving a specific function.
.text: The .text section is where the actual compiled code lives. With IDA we can analyze its decompiled version here..rodata: The .rodata section is where constants live. In fact, "rodata" stands for read-only data, exactly what a constant value is..data: The .data section stores the global variables of the program that are initialized with a value. Here we can see that the "ro" is no
longer there, because this section is RW, meaning that writing to it would not cause any problems..bss: The .bss section is very similar to .data, with the only difference being that it stores only the global variables that are NOT initialized.
To clarify what we are talking about, take the following code as an example:
#include <stdio.h>
#include <stdlib.h>
char not_initialized[8];
int initialized = 1337;
const char constant[16] = "i'm a constant";
int main(){
int local_variable = 1;
int second_local_variable = local_variable + 10;
printf("%d",second_local_variable);
printf("%s",constant);
printf("%d",initialized);
fgets(not_initialized,8,stdin);
return 0;
}
We can see that there are three global variables, each with different characteristics.
With IDA we can analyze the binary produced by compiling this code, and find out that:
-
not_initializedis in.bss: -
initializedis in.data: -
constantis in.rodata:
-
The compiled
mainfunction itself, along with the rest of the program's code, lives in.text:
There are two other very important sections, called .got and .plt.
These introduce a new concept: Dynamic Linking.
A Dynamically Linked program is simply one that relies on functions the developer did not write themselves,
for example the printf function used in a simple C program. printf is part of libc, a library
that contains a ton of useful functions used daily in C and C++ programs.
So, how can a function from the library actually be used in a Dynamically Linked program?
.plt
To keep things simple we will just give a brief introduction to this section, which will later be explained
in more detail in other topics in the pwn chapter.
When a program starts, it doesn't yet know where those libc functions are. In fact, the .plt section is the
one that resolves them, with the help of some dedicated functions. For each libc function present in the
executable, the .plt stores an entry that tells the resolver which function's address it needs to find.
This way, the first time you call printf the program resolves its address and then stores it in the .got.

.got
As we already hinted, the .got is the section that stores the resolved addresses of the library functions.
In fact, whenever a function is called, it first "asks" the GOT. If the GOT entry for that function is already
filled in, it uses the address that's there; otherwise, it starts the process where the .plt gets involved.