Intro

This is the second post of a blog series following my progress with the “Practical Reverse Engineering: x86, x64, ARM, Windows Kernel, Reversing Tools, and Obfuscation”, Bruce Dang, Alexandre Gazet, Elias Bachaalany, Sebastien Josse, ISBN: 978-1-118-78731-1.

The book includes number of exercises and the authors encourage the people to blog their solutions.
The solutions in this blog (source code and write-up PDFs) could be found also at https://github.com/malchugan/PRE-Exercises.

This time not much explanations in my writeup but most of the things are kind of obvious.

Chapter1-Exercise2 – Task

“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?
2. Come up with at least two code sequences to set EIP to 0xAABBCCDD.
3. In the example function, addme, what would happen if the stack pointer were not properly restored before executing RET?
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?”
Excerpt from: “Practical Reverse Engineering: x86, x64, ARM, Windows Kernel, Reversing Tools, and Obfuscation”, Bruce Dang, Alexandre Gazet, Elias Bachaalany, Sebastien Josse, ISBN: 978-1-118-78731-1

My Short answers

1. According to the “Intel® 64 and IA-32 Architectures Developer’s Manual: Vol. 1” the EIP register is not designed to be accessed directly by the software and could be affected implicitly only by handful of control flow instructions. In order to read the value of the EIP register one needs to execute CALL instruction to a function. CALL saves the EIP value in the stack as the function return address. While in the function body one could read the return address saved in the stack.
2. Here are some possible options for setting EIP to 0xAABBCCDD
Version A

...
MOV EAX, AABBCCDDh 
JMP EAX

Version B

 ...
MOV EAX, AABBCCDDh
CALL EAX
...

Version C

 ...
MOV EAX, AABBCCDDh 
PUSH EAX
RET
...

3. The execution will NOT continue from the saved return address but from completely different address
4. In case a function return value exceeds 32 bits, stack space is allocated to accommodate the function result
and EAX is initialised with pointer to that memory. To verify this answer I used a C program which defines a function concatenating 2 strings with result string bigger than 32 bit. I used 2 compilers – GCC under Linux and LCC under Windows. Both compilers implemented the same mechanism.

Code snippets

Read EIP value

Here is my suggestion for reading EIP value.
ex2_1-intel.asm listing

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
   global _start 
 
section .text
 
read_eip:
    push ebp
    mov ebp, esp
    mov eax, [ebp+4] ; move the return value in the EAX register mov esp, ebp
    pop ebp
    ret
_start:
    xor eax, eax
    call read_eip ; after returning from this function the EAX contains the EIP value ; exit gracefully
    mov eax, 1
    mov ebx, 0
    int 080h

I used IDA Debuger to trace the program execution and monitor the registers. The following screenshot illustrates a step after the call read_eip instruction.

Reading EIP

Set EIP to 0xAABBCCDD – Version A

ex2_2a.asm listing

1
2
3
4
5
6
    global _start 
section .text
 
_start:
   mov eax, 0AABBCCDDh
   jmp eax

Set EIP to 0xAABBCCDD – Version B

ex2_2b.asm listing

1
2
3
4
5
6
    global _start 
section .text
 
_start:
   mov eax, 0AABBCCDDh
   call eax

Set EIP to 0xAABBCCDD – Version C

ex2_2c.asm listing

1
2
3
4
5
6
7
    global _start 
section .text
 
_start:
   mov eax, 0AABBCCDDh
   push eax
   ret

Handling return values bigger than EAX size

I used the following C program to verify my theory regarding hot function return values bigger than 32b are handled.

ex2_3.c listing

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h>
 
char* stringConcat(char* s1, char* s2) {
   char* result = malloc(strlen(s1)+strlen(s2)+1); 
   strcpy(result, s1);
   strcat(result, s2); return result;
}
 
int main() { 
   char* r;
   char* a = "Test "; 
   char* b = "string";
   r = stringConcat(a, b); 
return 0;

After compiling it with 2 different compilers I disassembled and traced the executables with IDA. Line 32 in the disassembled function clearly indicate that the return value stored in EAX is a pointer to a memory location holding the function result.
Disassembled stringConcat function (part of the ELF executable generated with GCC) looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
.text:080484BC                 ; int __cdecl stringConcat(char *s, char *src)
.text:080484BC                 public stringConcat
.text:080484BC stringConcat    proc near               ; CODE XREF: main+28p
.text:080484BC
.text:080484BC dest            = dword ptr -0Ch
.text:080484BC s               = dword ptr  8
.text:080484BC src             = dword ptr  0Ch
.text:080484BC
.text:080484C0                 sub     esp, 24h
.text:080484C3                 mov     eax, [ebp+s]
.text:080484C6                 mov     [esp], eax      ; s
.text:080484C9                 call    _strlen
.text:080484CE                 mov     ebx, eax
.text:080484D0                 mov     eax, [ebp+src]
.text:080484D3                 mov     [esp], eax      ; s
.text:080484D6                 call    _strlen
.text:080484DB                 add     eax, ebx
.text:080484DD                 add     eax, 1
.text:080484E0                 mov     [esp], eax      ; size
.text:080484E3                 call    _malloc
.text:080484E8                 mov     [ebp+dest], eax
.text:080484EB                 mov     eax, [ebp+s]
.text:080484EE                 mov     [esp+4], eax    ; src
.text:080484F2                 mov     eax, [ebp+dest]
.text:080484F5                 mov     [esp], eax      ; dest
.text:080484F8                 call    _strcpy
.text:080484FD                 mov     eax, [ebp+src]
.text:08048500                 mov     [esp+4], eax    ; src
.text:08048504                 mov     eax, [ebp+dest]
.text:08048507                 mov     [esp], eax      ; dest
.text:0804850A                 call    _strcat
.text:0804850F                 mov     eax, [ebp+dest]
.text:08048512                 add     esp, 24h
.text:08048515                 pop     ebx
.text:08048516                 pop     ebp
.text:08048517                 retn
Practical Reverse Engineering Exercises – Ch1-Ex2 – Write-Up

Leave a Reply

Your email address will not be published. Required fields are marked *

*