Skip to main content

EIP

Definition​

EIP is Extended Instruction Pointer.

It's a register in x86 architecture (32-bit), its 64 version is called "RIP".

The EIP is used to store the address of the next instruction.

When calling a function, the EIP is stored beneath the stack frame of the called function.

This is what we have seen in the diagram.

Stack frame​

As shown earlier, the stack is used to store temporary variables (i.e: local variables, arguments).

Each function has its own stack frame, meaning everything in-between the esp (top of the stack) and ebp (bottom of the stack).

Simple calls​

So each time you call a new function, a new stack frame is added, with its own local variables.

For example, let's take 3 calls to the same function, one after each other.

int func(int a, int b, int c)
{
int local_var1 = 0;
int local_var2 = 1;
int local_var3 = 2;

return 0;
}

int main()
{
func(1, 2, 3);
func(4, 5, 6);
func(7, 8, 9);
return 0;
}

The stack will look like this :

Successive calls​

int two()
{
return 0;
}

int one()
{
two();
return 0;
}

int main()
{
one();
return 0;
}

Also, you can observe the presence of EIP below each stack frame. When you call a function, you store the EIP (next instruction) before setting a new stackframe. When you end a function, the saved EIP is used to go back to where we were, and resume execution after the call.

Setting a new stack frame and removing it is the job of the prologue and the epilogue, which is present in each function.

Prologue​

By disassembling binaries, you can observe some patterns in the code, especially at the beginning and ending of functions.

main.c
int hello()
{
char buffer[20] = {0};
return 1;
}

int main()
{
return hello();
}
gcc main.c -o main -m32     # compile for 32-bit
objdump -d -M intel main # disassemble
0000117d <hello>:
117d: 55 push ebp
117e: 89 e5 mov ebp,esp
1180: 83 ec 20 sub esp,0x20
1183: e8 7d 00 00 00 call 1205 <__x86.get_pc_thunk.ax>
1188: 05 6c 2e 00 00 add eax,0x2e6c

# ...

000011b7 <main>:
11b7: 55 push ebp
11b8: 89 e5 mov ebp,esp
11ba: 83 ec 20 sub esp,0x20
11bd: e8 43 00 00 00 call 1205 <__x86.get_pc_thunk.ax>
11c2: 05 32 2e 00 00 add eax,0x2e32
11c7: c7 45 e2 00 00 00 00 mov DWORD PTR [ebp-0x1e],0x0
# ...
11fe: e8 7a ff ff ff call 117d <hello>
# ...

That is the prologue.

Let's go through it step-by-step.

images

Epilogue​

0000117d <hello>:
117d: 55 push ebp
117e: 89 e5 mov ebp,esp
1180: 83 ec 20 sub esp,0x20
# ...
11a9: c7 45 fc 00 00 00 00 mov DWORD PTR [ebp-0x4],0x0
11b0: b8 01 00 00 00 mov eax,0x1
11b5: c9 leave
11b6: c3 ret

000011b7 <main>:
11b7: 55 push ebp
11b8: 89 e5 mov ebp,esp
11ba: 83 ec 20 sub esp,0x20
# ...
11fe: e8 7a ff ff ff call 117d <hello>
1203: c9 leave
1204: c3 ret

The epilogue is the 2 last instructions of a function.

The leave instruction is short for

mov esp, ebp
pop ebp

Then ret is like:

pop eip

Stepping through step-by-step:

images