Lets Look At The Stack.

Memory

Buffer overflows are a violation of memory safety.  To understand them we need to understand memory first.  There are five memory segments associated with a program loaded into memory for execution.  There are three we aren’t really that concerned with.  The text, data, and bss segments.  These segments are fixed size.  The text segment contains the code for the program execution and is not writable.  The data and bss segments are used for storing initialized global and static variables and uninitialized global and static variables respectively.

The other two memory segments are the heap and the stack.  We are going to focus on the stack right now.  We will get to the heap later.  For now I’ll just say that the heap is dynamic memory available to the programmer.

The Stack

The stack is dynamically allocated memory used to store function information and local variables during function calls.  It follows a First In Last Out (FILO) structure.  The stack always grows towards lower memory addresses.  Some refer to this as growing downward or upward, it just depends on the author.  At first this may be hard to visualize.  What it means that when we add information to the stack the top of the stack will actually have a lower memory address than before.  When we take information off the stack the memory address of the top of the stack will be higher than before.

When the function is called a stack frame, all the information for that function, is pushed onto the stack.  There are some registers we want to pay attention to that are on the stack.  In 32-bit systems those registers are EIP, EBP, and ESP.  In 64-bit systems those registers become RIP, RBP, and RSP.  The stack frame also contains two pointers. The SFP (saved frame pointer) to restore EBP to its previous value, and the return address to restore EIP.

The Registers

The EIP (instruction pointer) register contains the memory address of the next instruction to execute.  The address to send EIP after the function has finished is stored in the stack frame.  The ESP (stack pointer) register is used to keep track of the address at the end of the stack.  The EBP (base pointer) register is used to point to the local variables contained in a stack frame.

Lets Look At The Stack.

When I really want to understand something I try to break it down as simple as possible.  The following program is about the simplest program I could think of that uses a function.

//A program to look at the stack.

//Really simple function that takes 1 parameter.
void function(int a) {
    
    int test;
    
    //assign the variable test the value of a.
    test = a;
}

int main(void) {
    
    //call the function.
    function(1);
}

We have a function that takes one parameter and all it does is assign the passed value to an uninitialized variable. We are going to take a deeper look at what happens by running this program through gdb.

$ gcc -g -o stack1 stack1.c -fno-stack-protector
$ gdb -q ./stack1  

There really isn’t a need to use the stack protector flag for this program but I ran it anyway. Once we are in gdb we can look at the code loaded into the memory.

Reading symbols from ./stack1...done.
(gdb) disass main
Dump of assembler code for function main:
   0x080483d9 <+0>:     push   ebp
   0x080483da <+1>:     mov    ebp,esp
   0x080483dc <+3>:     push   0x1
   0x080483de <+5>:     call   0x80483cb  <function>
   0x080483e3 <+10>:    add    esp,0x4
   0x080483e6 <+13>:    leave  
   0x080483e7 <+14>:    ret    
End of assembler dump.

The first line here is showing that the program is pushing ebp onto the stack, the instruction so contained in memory address 0x080483d9 which is the hex representation of the address. Then the next instruction moves esp to ebp. These two lines are setting up the stack frame.  Then we see that the value 0x1 is pushed on the stack.  Then function is called. Next we have that esp is incremented by 0x4 = 4. Then the leave instruction destroys the stack frame. Finally ret pops EIP from the stack and jumps to that address.

We can do the same thing with function.

(gdb) disass function
Dump of assembler code for function function:
   0x080483cb <+0>:     push   ebp
   0x080483cc <+1>:     mov    ebp,esp
   0x080483ce <+3>:     sub    esp,0x10
   0x080483d1 <+6>:     mov    eax,DWORD PTR [ebp+0x8]
   0x080483d4 <+9>:     mov    DWORD PTR [ebp-0x4],eax
   0x080483d7 <+12>:    leave  
   0x080483d8 <+13>:    ret    
End of assembler dump. 

We see the first pair of instructions are the same for function as for main. This is where the stack frame is being set up for function. We can compare the addresses for the beginning of main and the beginning of function to see that 0x080483cb < 0x080483d9. Which is our stack growing towards lower addresses. We also can see that the call instruction in main is holding the address of the base of the stack frame for function.  At 0x080483ce we are subtracting 0x10 = 16 from the value in esp.  Next we are moving around values.  We move the value of ebp+0x8 into the eax register.  Then we move the value of eax to ebp-0x4.  If we are paying attention to what our original program was doing we can guess that these are the instructions of passing our value to function and assigning the variable test = 1.

Now that we’ve examined the program as it’s loaded into memory for execution we can set some break points and run the program to look at what actually occurs.

(gdb) list function
1       //A program to look at the stack.
2
3       //Really simple function that takes 1 parameter.
4       void function(int a) {
5           
6           int test;
7           
8           //assign the variable test the value of a.
9           test = a;
10      }
(gdb) 
11
12      int main(void) {
13          
14          //call the function.
15          function(1);
16      }

We want to put breaks at the main actions of our program so we put one at the function call in main and then at the start of the execution of function. Then we start running the program and we can examine the memory as the program executes.

(gdb) break 15
Breakpoint 1 at 0x80483dc: file stack1.c, line 15.
(gdb) break function
Breakpoint 2 at 0x80483d1: file stack1.c, line 9.
(gdb) run
Starting program: /home/exploit/Hacking/Programming/stack1 

Breakpoint 1, main () at stack1.c:15
15          function(1);
(gdb) i r esp ebp eip
esp            0xbffff2a8       0xbffff2a8
ebp            0xbffff2a8       0xbffff2a8
eip            0x80483dc        0x80483dc <main+3>

We can see that the pointers esp and ebp have the same value. We also see that eip is pointing at the instruction to push 1 onto the stack.  If we look back at the disassemble main output we see that this is just before the function call.

Continuing and examining the pointers again we get the following output:

(gdb) cont
Continuing.

Breakpoint 2, function (a=1) at stack1.c:9
9           test = a;
(gdb) i r esp ebp eip
esp            0xbffff28c       0xbffff28c
ebp            0xbffff29c       0xbffff29c
eip            0x80483d1        0x80483d1 <function+6>

We see that our registers are pointing at different memory addresses. The eip is pointing at the instruction to assign the value 1 to the test variable. We also see that the values of esp and ebp have decreased since we have moved esp to the end of the function stack frame and ebp is now pointing to local variables inside the function stack frame. Note that esp is less than ebp in value. This is a nice illustration of the stack growing towards lower memory addresses. We can use gdb to examine what the locations pointed at in our instructions look like before execution as well.

(gdb) print $ebp+0x8
$1 = (void *) 0xbffff2a4
(gdb) print $ebp-0x4
$2 = (void *) 0xbffff298

Here we see the memory addresses of the pointers in function.  Which are the addresses that are being moved in function.  We are moving $1 into eax and then moving eax into $2.

(gdb) x/8xw $esp
0xbffff28c:     0xb7e453fd      0xb7fbd3c4      0xb7fff000      0x080483fb
0xbffff29c:  (3)0xbffff2a8   (2)0x080483e3   (1)0x00000001      0x00000000

The first thing that jumps out is the value passed to our function (1). The next thing that jumped out to me was the address of the next instruction after the function call in main at (2). At (3) we have the address of the top of the main stack frame, which is the value of the saved frame pointer.

Now if we modify our program to include a second variable passed to function and examine the stack again we get the following:

(gdb) x/8xw $esp
0xbffff288:     0xbffff34c      0xb7e453fd      0xb7fbd3c4      0xb7fff000
0xbffff298:     0xbffff2a8      0x080483eb      0x00000001      0x00000002

We have that our variables are at the base of the stack again. Then we have that the next instruction in main is saved directly above them. Then we have the saved frame pointer is again just above that.  From here we can modify our program with different data structures to see how the stack is modified if we want.

Conclusion.

Even though we were working with a trivial program in this post we have covered a lot of information.  We got some great hands on practice at running a program through gdb.  We also got an introduction to registers in action.  We could see how EIP, ESP, and EBP changed during the execution of our program by using break points during execution.  Hopefully with all the material we covered here we will be able to understand a little more about what happens when we start breaking the functionality of the stack and the C programming language for our own purposes.

Credits.

I used Hacking The Art of Exploitation heavily as a resource for this post.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s