0

I've started learning the Reverse Engineering and when I read the Stack Operations and function invocation, there are an issue that I'm confused. -What is the address of ESP after "pop ebp" and "retn" instruction??

C program

int __cdecl addme(short a, short b)
{
     return a+b;
}

Assembly program

01: push ebp
02: mov ebp , esp
03:...
04:movsx eax ,word ptr [ebp+8]
05:movsx ecx ,word ptr [ebp+0Ch]
06:add eax ,ecx
07:...
08:mov esp , ebp
09:pop ebp
10:retn

As I though , esp is set to ebp in step 08 so the ESP address is right after the the first address comes inside the stack.But the step 09 makes it wrong. Help me understand this.

1

To further expand on perrors answer, you're looking at a function that preserves the stack frame, which is a nice little trick to simplify walking backwards through the call stack. When you initially push EBP in the prologue, it subtracts pointer size (which is of course 0x4 in x86) before writing the old EBP to the stack, as seen below in equivalent code.

SUB ESP, 0x4 ; Result from PUSH  
MOV [ESP], EBP ; Save old EBP  
MOV EBP, ESP ; Set new EBP  

Now once it reaches the epilogue and restores the stack pointer (ESP) from the frame pointer (EBP) it's still 4 bytes below the original stack when entering the function. What's at the current stack pointer? It holds the previous frame pointer from before invoking the current function. By popping EBP you are both restoring the frame pointer to what it was and fixing the stack at the same time, as shown below.

MOV ESP, EBP ; Restore ESP from prologue  
MOV EBP, [ESP] ; Restore saved EBP  
ADD ESP, 0x4 ; Result from POP  

The return following this can be interpreted as a POP EIP instruction, as shown below.

MOV EIP, [ESP] ; Redirect execution to return address  
ADD ESP, 0x4 ; Result from pop  

I should also add that CALL can be simplified as a push/jump, as shown below.

SUB ESP, 0x4 ; Result from PUSH  
MOV [ESP], ReturnAddress ; Save next instruction as return address  
JMP CallAddress ; Redirect execution to call address  

As you can probably see, this allows you to simply work backwards to get both the frame pointer and return address from previous function calls that led to the current function. Hopefully that explains both the purpose and logic behind the frame pointer preservation your question is based on.

Note: In terms of the post by perror, I also wanted to point out a couple things. First the constant 0x4 should be sizeof(uintptr_t). I know your code is x86 so he's not wrong, it's just good to know. Second is that push can be thought of as subtracting the stack before setting the value, while pop can be thought of as the exact opposite, getting the value first before adding the stack.

| improve this answer | |
1

The esp is updated when a push or a pop is called. Remember that the esp is used to point to the current last item on the stack. So, each push or pop operation move it up or down.

To be more explicit, we can decompose in smaller instructions (only mov) the pop and the push as follow:

pop ebp == (mov ebp, [esp] ; mov esp, esp + 4)
push ebp == (mov [esp], ebp ; mov esp, esp - 4)

I hope this is just clearer now.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.