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