1. How Buffer Overflows work: the stack
How the Stack Works: Part 1 - Return Addresses and Function Calls
Released on 8/16/2015
[Instructor] We're going to take a look
at
1. How Buffer Overflows work: the stack
How the Stack Works: Part 1 - Return Addresses and Function Calls
Released on 8/16/2015
[Instructor] We're going to take a look
at how the stack works and how it's manipulated
by function calls, and to do that we're going
to use a very simple little program.
Our program has two functions.
Main which is where every C and C++ program starts,
and main will just call say hello.
Say hello will print a message on screen
to ask us for our name.
It will then create a 64-character buffer
and read from the keyboard into that buffer,
and then it will print out another message
using the buffer say hello to us.
So, if I run the program,
we get our prompt, can type in my name,
and there we go: Hello, Peter.
I'm going to use the debugger to look inside the program
as it's running so that we can see the stack
and see how the different parts of the program fit together.
So I'm going to stop at this red dot
just before it calls say hello.
The debugger is quite a bit more complicated
than the basic editor.
We still have our editor window with us up here,
but we also have a bunch of other panes.
This pane shows local variables.
We don't actually have any at the moment
so it doesn't show anything.
Up here we have a bunch of stuff.
This assembly window shows us the executable code
that makes up the program,
and it shows it in a few different ways altogether.
So we have fragments of the source code,
and then, interspersed with them we have the machine code
which is the actual compiled binary representation
that the processor actually uses.
And we have the assembler which is a kind of human
readable equivalent to the machine code.
Next to each bit of machine code
we have the memory addresses of the code
because every piece of code has its own memory address.
Down here we have some of the processor's registers,
and there're two registers that really interest us.
The first is EIP which is the memory address
of the instruction that's about to execute
if the program is running the address
of the currently executing instruction.
So that at the moment is set to 401043,
and if we look in the disassembly window
the address is 401043,
is the address of this call instruction.
So, it's stopped just before we make the call.
The other really important register is ESP
which is the stack pointer.
That's currently 19ff28.
I have this pane over here.
This is showing us the processor's memory.
I've got it set up so the top line of this window
is always the address that ESP contains.
So that means this line here
is always the top of the stack.
ESP will change.
Every time something is pushed onto the stack,
ESP will get reduced,
and every time something is popped from the stack,
ESP will increase.
But it will always be this top line here.
So we're stopped just before the call instruction.
The call instruction does
a couple of things together all as one.
The first thing it does is it pushes the return address
onto the stack.
So the return address is the address we come back to
when the function, in this case say hello, is finished.
That is the address of the instruction
immediately after the called instruction.
So our return address is 401048.
So that's what call needs to push onto the stack.
To push it onto the stack it will first make space,
on the top of the stack, so this is a full bite number,
so it will reduce ESP by 4, change it by 4 bites.
That now will give memory address 19ff24,
and then, into address 19ff24
it will write this value, 401048.
That means the top of the stack
will contain the return value.
The other thing that called instruction does
is it changes EIP, the instruction pointer.
It will change it to, in this instance 401000,
which is the address of the say hello function.
So if I run just the called instruction on its own
and then stop immediately after,
we will see that both of these things happen.
The return address will get pushed onto the stack,
and EIP will change to 401000.
And there we have it.
and it's this instruction.
As we can see from the disassembly window,
the start of the say hello function,
and ESP is now 19ff24.
And what do we see at 19ff24 in memory?
We see 401048, which is our return address.
The counterpart to call is return,
which is called ret.
So I will just run the program until it gets there.
And here we are stopped at ret.
Ret does the opposite of call,
so it will pop the re