I'm taking a class in Language Based Security and I have to know step by step what is happening in the stack when a function is executed properly, so that later I can learn how to protect against exploits. So far I have a pretty good understanding of what is pushed and popped from the stack and how the ESP, EBP move about to keep track of frames. Also, I know that the EIP is saved on the stack.
What I don't know is where the code in the function is actually executed to get a result (I presume somewhere else in memory, the Heap?) If I give a walkthrough of a simple function, can someone explain the missing bits (I'll tag those parts with questions). Presume a simple function:
int add(int x, int y)
{
int sum = x + y;
return sum;
}
which is called in main() with add(3,4);
At the initialization of a new function, the stack (from lowest address to highest) has the ESP pointing to the top and the EBP pointing to the base of the new frame. Below that is main().
Now, the parameters are pushed onto the stack from right to left. The the function call saves the contents of EIP on the stack. [This is the address of the next instruction to be executed after the function returns?]
Now the Prolog part: The old EBP address is pushed onto stack and the EBP is made to point to the ESP. Finally, the local variables are pushed onto the stack [Are these just the addresses of where their values are stored?]
The Epilog is when the stack is to be unwound for the current frame. ESP is moved to EBP, so that local variables are inaccessible (normally). Old EBP is popped off stack, and made to point to its original address. ESP moves to point to saved EIP which was where it was before add(3,4) was called.
In the explanation I was given to study, the final part is that the return instruction pops the saved EIP value back into the EIP register. [Surely this isn't the return statement in the function but a ret instruction at machine level, right?]
Last question, can someone explain what's going on when the code in the function is executing and at what point during all that does the call, prolog and epilog occur? Or provide a good link to a clear explanation?
Thanks heaps in advance (so to speak :)
int i;
orchar *ptr
cannot overflow the stack, but arrays such aschar[20];
can, and arrays using memory dynamically allocated tochar *ptr
can overflow the allocation on the heap. – Weather Vanecall
instruction is executed, the address of the instruction following thecall
is pushed on the stack. Function local variables are usually not pushed on the stack - rather the stack pointer is decremented to allocate needed storage for locals, which are initialized later. And thereturn
is indeed an assembly instruction. – Craig S. Anderson