Solution to Practical Reverse Engineering II. Chapter 01, Page 17

The next round of exercises starts with the following:

1. Given what you learned about CALL and RET, explain how you would read the value of EIP? Why can’t you just do MOV EAX, EIP?

I can’t do mov eax, eip because this register is implicitly controlled by the transfer instructions (jmp, call, etc.).
From the Intel manual:

3.5 INSTRUCTION POINTER
The instruction pointer (EIP) register contains the offset in the current code segment for the next instruction to be executed. It is advanced from one instruction boundary to the next in straight-line code or it is moved ahead or backwards by a number of instructions when executing JMP, Jcc, CALL, RET, and IRET instructions.

My solution was the following:

GLOBAL _start
 
_start: 
    nop
    call foo
    nop
    nop
    nop
 
foo:
    pop eax
    push eax
    ret

I created the auxiliary function foo to call it. By using call, we are pushing EIP to the stack. Then, in the function, we pop in eax the value on the top of the stack, i.e. the value of the next instruction after the ret, which is exactly the value we want.
To return to the next instruction, I put the return address back in the stack by pushing eax, and I return to it.
After the execution of foo we will have the value of eip in the eax register.

2. Come up with at least two code sequences to set EIP to 0xAABBCCDD.

jmp AABBCCDDh
call AABBCCDDh
push AABBCCDDh
ret

3. In the example function, addme, what would happen if the stack pointer were not properly restored before executing RET?

TL;DR: Nothing at all.
Let’s see the code of the program:

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

In Assembly:

004113A0 55             push ebp
004113A1 8B EC          mov ebp, esp
...
004113BE 0F BF 45 08    movsx eax, word ptr [ebp+8]
004113C2 0F BF 4D 0C    movsx ecx, word ptr [ebp+0Ch]
004113C6 03 C1          add eax, ecx
...
004113CB 8B E5          mov esp, ebp
004113CD 5D             pop ebp
004113CE C3             retn

The stack is not modified during the execution of the code. This means the stack pointer (esp) is not modified during the execution of the function.
When the flow reaches the restoration instruction, the stack will look like the following:

eip->   004113CB 8B E5          mov esp, ebp
        004113CD 5D             pop ebp
        004113CE C3             retn
       |----------|
       |     b    |
EBP+C->|----------|
       |     a    |
EBP+8->|----------|
       |  Return  |
EBP+4->|----------|
       |    EBP   |
  EBP->|----------|<-ESP
       |          |

By executing the instruction mov esp, ebp, we are making esp point to ebp. Since esp was already pointing to ebp, it does nothing.
Then the function epilogue does its job.
So, as I stated before, nothing happens.

4. In all of the calling conventions explained, the return value is stored in a 32-bit register (EAX). What happens when the return value does not fit in a 32-bit register? Write a program to experiment and evaluate your answer. Does the mechanism change from compiler to compiler?

To force the return of a value bigger than a 32-bit register, I will use the structure Test in the following program:

#include <stdio.h>

typedef struct{
	int a;
	int b;
}Test;
Test foo(){
	Test bar;
	bar.a = 5;
	bar.b = 7;
	return bar;
}


int main(){
	Test res;
	res = foo();
	printf("%d/%d", res.a, res.b);
	return 0;
}

After compiling it in a 32-bits system, the disassembly of the function looks like this:

0804841d <foo>:
 804841d:	55                   	push   ebp
 804841e:	89 e5                	mov    ebp,esp
 8048420:	83 ec 10             	sub    esp,0x10
 8048423:	c7 45 f8 05 00 00 00 	mov    DWORD PTR [ebp-0x8],0x5
 804842a:	c7 45 fc 07 00 00 00 	mov    DWORD PTR [ebp-0x4],0x7
 8048431:	8b 4d 08             	mov    ecx,DWORD PTR [ebp+0x8]
 8048434:	8b 45 f8             	mov    eax,DWORD PTR [ebp-0x8]
 8048437:	8b 55 fc             	mov    edx,DWORD PTR [ebp-0x4]
 804843a:	89 01                	mov    DWORD PTR [ecx],eax
 804843c:	89 51 04             	mov    DWORD PTR [ecx+0x4],edx
 804843f:	8b 45 08             	mov    eax,DWORD PTR [ebp+0x8]
 8048442:	c9                   	leave  
 8048443:	c2 04 00             	ret    0x4

In order to see what exactly is going on, I am going to debug the function foo. To do that, we can set a break point in foo or just execute step by step until the call.

(gdb) si
0x0804841d in foo ()
9: x/32xw $esp
0xbffff06c:	0x08048462	0xbffff088	0x0000002f	0x0804a000
0xbffff07c:	0x080484e2	0x00000001	0xbffff144	0xbffff14c
0xbffff08c:	0xb7e4975d	0xb7fc23c4	0xbffff0b0	0x00000000
0xbffff09c:	0xb7e2fa83	0x08048490	0x00000000	0x00000000
0xbffff0ac:	0xb7e2fa83	0x00000001	0xbffff144	0xbffff14c
0xbffff0bc:	0xb7feccea	0x00000001	0xbffff144	0xbffff0e4
0xbffff0cc:	0x0804a014	0x0804821c	0xb7fc2000	0x00000000
0xbffff0dc:	0x00000000	0x00000000	0xf0e21483	0xcaf7f093
8: /x $ebp = 0xbffff098
7: /x $esi = 0x0
6: /x $edi = 0x0
5: /x $edx = 0xbffff0d4
4: /x $ecx = 0xbffff0b0
3: /x $ebx = 0xb7fc2000
2: /x $eax = 0xbffff088
1: x/10i $eip
=> 0x804841d :	push   ebp
   0x804841e :	mov    ebp,esp
   0x8048420 :	sub    esp,0x10
   0x8048423 :	mov    DWORD PTR [ebp-0x8],0x5
   0x804842a :	mov    DWORD PTR [ebp-0x4],0x7
   0x8048431 :	mov    ecx,DWORD PTR [ebp+0x8]
   0x8048434 :	mov    eax,DWORD PTR [ebp-0x8]
   0x8048437 :	mov    edx,DWORD PTR [ebp-0x4]
   0x804843a :	mov    DWORD PTR [ecx],eax
   0x804843c :	mov    DWORD PTR [ecx+0x4],edx

We are in the beginning of foo.

After executing the prologue of the function, we have the following values in the stack and registries:

Breakpoint 2, 0x08048423 in foo ()
9: x/32xw $esp
0xbffff058:	0xb7e22bf8	0xb7e495a3	0x00000000	0x00ca0000
0xbffff068:	0xbffff098	0x08048462	0xbffff088	0x0000002f
0xbffff078:	0x0804a000	0x080484e2	0x00000001	0xbffff144
0xbffff088:	0xbffff14c	0xb7e4975d	0xb7fc23c4	0xbffff0b0
0xbffff098:	0x00000000	0xb7e2fa83	0x08048490	0x00000000
0xbffff0a8:	0x00000000	0xb7e2fa83	0x00000001	0xbffff144
0xbffff0b8:	0xbffff14c	0xb7feccea	0x00000001	0xbffff144
0xbffff0c8:	0xbffff0e4	0x0804a014	0x0804821c	0xb7fc2000
8: /x $ebp = 0xbffff068
7: /x $esi = 0x0
6: /x $edi = 0x0
5: /x $edx = 0xbffff0d4
4: /x $ecx = 0xbffff0b0
3: /x $ebx = 0xb7fc2000
2: /x $eax = 0xbffff088
1: x/10i $eip
=> 0x8048423 :	mov    DWORD PTR [ebp-0x8],0x5
   0x804842a :	mov    DWORD PTR [ebp-0x4],0x7
   0x8048431 :	mov    ecx,DWORD PTR [ebp+0x8]
   0x8048434 :	mov    eax,DWORD PTR [ebp-0x8]
   0x8048437 :	mov    edx,DWORD PTR [ebp-0x4]
   0x804843a :	mov    DWORD PTR [ecx],eax
   0x804843c :	mov    DWORD PTR [ecx+0x4],edx
   0x804843f :	mov    eax,DWORD PTR [ebp+0x8]
   0x8048442 :	leave  
   0x8048443 :	ret    0x4

After executing the two lines marked in bold, we can see the two values assigned to the structure in the stack (ebp - 8 and ebp - 4)

(gdb) si
0x08048431 in foo ()
9: x/32xw $esp
0xbffff058:	0xb7e22bf8	0xb7e495a3	0x00000005	0x00000007
0xbffff068:	0xbffff098	0x08048462	0xbffff088	0x0000002f
0xbffff078:	0x0804a000	0x080484e2	0x00000001	0xbffff144
0xbffff088:	0xbffff14c	0xb7e4975d	0xb7fc23c4	0xbffff0b0
0xbffff098:	0x00000000	0xb7e2fa83	0x08048490	0x00000000
0xbffff0a8:	0x00000000	0xb7e2fa83	0x00000001	0xbffff144
0xbffff0b8:	0xbffff14c	0xb7feccea	0x00000001	0xbffff144
0xbffff0c8:	0xbffff0e4	0x0804a014	0x0804821c	0xb7fc2000
8: /x $ebp = 0xbffff068
7: /x $esi = 0x0
6: /x $edi = 0x0
5: /x $edx = 0xbffff0d4
4: /x $ecx = 0xbffff0b0
3: /x $ebx = 0xb7fc2000
2: /x $eax = 0xbffff088
1: x/10i $eip
=> 0x8048431 :	mov    ecx,DWORD PTR [ebp+0x8]
   0x8048434 :	mov    eax,DWORD PTR [ebp-0x8]
   0x8048437 :	mov    edx,DWORD PTR [ebp-0x4]
   0x804843a :	mov    DWORD PTR [ecx],eax
   0x804843c :	mov    DWORD PTR [ecx+0x4],edx
   0x804843f :	mov    eax,DWORD PTR [ebp+0x8]
   0x8048442 :	leave  
   0x8048443 :	ret    0x4

Then it takes the value stored in ebp+0x8 and stores it in ecx.

(gdb) si
0x08048434 in foo ()
9: x/32xw $esp
0xbffff058:	0xb7e22bf8	0xb7e495a3	0x00000005	0x00000007
0xbffff068:	0xbffff098	0x08048462	0xbffff088	0x0000002f
0xbffff078:	0x0804a000	0x080484e2	0x00000001	0xbffff144
0xbffff088:	0xbffff14c	0xb7e4975d	0xb7fc23c4	0xbffff0b0
0xbffff098:	0x00000000	0xb7e2fa83	0x08048490	0x00000000
0xbffff0a8:	0x00000000	0xb7e2fa83	0x00000001	0xbffff144
0xbffff0b8:	0xbffff14c	0xb7feccea	0x00000001	0xbffff144
0xbffff0c8:	0xbffff0e4	0x0804a014	0x0804821c	0xb7fc2000
8: /x $ebp = 0xbffff068
7: /x $esi = 0x0
6: /x $edi = 0x0
5: /x $edx = 0xbffff0d4
4: /x $ecx = 0xbffff088
3: /x $ebx = 0xb7fc2000
2: /x $eax = 0xbffff088
1: x/10i $eip
=> 0x8048434 :	mov    eax,DWORD PTR [ebp-0x8]
   0x8048437 :	mov    edx,DWORD PTR [ebp-0x4]
   0x804843a :	mov    DWORD PTR [ecx],eax
   0x804843c :	mov    DWORD PTR [ecx+0x4],edx
   0x804843f :	mov    eax,DWORD PTR [ebp+0x8]
   0x8048442 :	leave  
   0x8048443 :	ret    0x4

By executing the next two instructions, marked in bold above, we will store the values of the elements of the structure in aex and edx.

(gdb) si
0x0804843a in foo ()
9: x/32xw $esp
0xbffff058:	0xb7e22bf8	0xb7e495a3	0x00000005	0x00000007
0xbffff068:	0xbffff098	0x08048462	0xbffff088	0x0000002f
0xbffff078:	0x0804a000	0x080484e2	0x00000001	0xbffff144
0xbffff088:	0xbffff14c	0xb7e4975d	0xb7fc23c4	0xbffff0b0
0xbffff098:	0x00000000	0xb7e2fa83	0x08048490	0x00000000
0xbffff0a8:	0x00000000	0xb7e2fa83	0x00000001	0xbffff144
0xbffff0b8:	0xbffff14c	0xb7feccea	0x00000001	0xbffff144
0xbffff0c8:	0xbffff0e4	0x0804a014	0x0804821c	0xb7fc2000
8: /x $ebp = 0xbffff068
7: /x $esi = 0x0
6: /x $edi = 0x0
5: /x $edx = 0x7
4: /x $ecx = 0xbffff088
3: /x $ebx = 0xb7fc2000
2: /x $eax = 0x5
1: x/10i $eip
=> 0x804843a :	mov    DWORD PTR [ecx],eax
   0x804843c :	mov    DWORD PTR [ecx+0x4],edx
   0x804843f :	mov    eax,DWORD PTR [ebp+0x8]
   0x8048442 :	leave  
   0x8048443 :	ret    0x4

The instructions marked in bold above will set the value in the address pointed by ecx to the value of eax, i.e. the first element of the structure. And right after that, it will store the value of the second element of the structure (edx).

(gdb) si
0x0804843f in foo ()
9: x/32xw $esp
0xbffff058:	0xb7e22bf8	0xb7e495a3	0x00000005	0x00000007
0xbffff068:	0xbffff098	0x08048462	0xbffff088	0x0000002f
0xbffff078:	0x0804a000	0x080484e2	0x00000001	0xbffff144
0xbffff088:	0x00000005	0x00000007	0xb7fc23c4	0xbffff0b0
0xbffff098:	0x00000000	0xb7e2fa83	0x08048490	0x00000000
0xbffff0a8:	0x00000000	0xb7e2fa83	0x00000001	0xbffff144
0xbffff0b8:	0xbffff14c	0xb7feccea	0x00000001	0xbffff144
0xbffff0c8:	0xbffff0e4	0x0804a014	0x0804821c	0xb7fc2000
8: /x $ebp = 0xbffff068
7: /x $esi = 0x0
6: /x $edi = 0x0
5: /x $edx = 0x7
4: /x $ecx = 0xbffff088
3: /x $ebx = 0xb7fc2000
2: /x $eax = 0x5
1: x/10i $eip
=> 0x804843f :	mov    eax,DWORD PTR [ebp+0x8]
   0x8048442 :	leave  
   0x8048443 :	ret    0x4

If we check the value of those addresses we can see they have the values of bar.a and bar.b. Those addresses happen to be part of the stack and the first one is the base address of the structure bar:

(gdb) x/x 0xbffff088
0xbffff088:	0x00000005
(gdb) x/x 0xbffff088+0x4
0xbffff08c:	0x00000007

The next instruction, mov eax,DWORD PTR [ebp+0x8] will set eax to 0xbffff088, the base address of the structure.

(gdb) si
0x08048442 in foo ()
9: x/32xw $esp
0xbffff058:	0xb7e22bf8	0xb7e495a3	0x00000005	0x00000007
0xbffff068:	0xbffff098	0x08048462	0xbffff088	0x0000002f
0xbffff078:	0x0804a000	0x080484e2	0x00000001	0xbffff144
0xbffff088:	0x00000005	0x00000007	0xb7fc23c4	0xbffff0b0
0xbffff098:	0x00000000	0xb7e2fa83	0x08048490	0x00000000
0xbffff0a8:	0x00000000	0xb7e2fa83	0x00000001	0xbffff144
0xbffff0b8:	0xbffff14c	0xb7feccea	0x00000001	0xbffff144
0xbffff0c8:	0xbffff0e4	0x0804a014	0x0804821c	0xb7fc2000
8: /x $ebp = 0xbffff068
7: /x $esi = 0x0
6: /x $edi = 0x0
5: /x $edx = 0x7
4: /x $ecx = 0xbffff088
3: /x $ebx = 0xb7fc2000
2: /x $eax = 0xbffff088
1: x/10i $eip
=> 0x8048442 :	leave  
   0x8048443 :	ret    0x4

Then we have the function epilogue. And that's it!
After this process, we can see that the value returned is an address pointing to a place in the stack. Therefore the value is returned in the stack.

0 comments