1 - A) Given what you learned about CALL and RET, explain how you would read the value of EIP ?
EIP is used to save the return address after a CALL or a RET for example. In this way, the program will resume correctly and it can continue the execution flow.
I’ll use a CALL to a function to modify EIP. Inside this function, we have to save the value of EIP inside a register. Next, we print the content of this register.
Code:
SECTION .text
GLOBAL _start
_start:
call store_eip
mov ebx,0
mov eax,1
int 080h
store_eip:
mov eax, [esp]
ret
Code Explaination:
- .text section is used for the program code (while .data is used for constants)
- GLOBAL _start is used to declare the symbol
- Call the function store_eip
- We set eax to the value pointed by esp Don’t forget: when a function is call without arguments, ESP point to the bottom of the stack which contain the value of the return address function (EIP)
- We use int 080h to use syscall. In our case, EAX = 0 so the syscall will be exit()
Installation des pré-requis:
sudo apt install nasm
Compilation:
$ nasm -f elf32 -g -F drawf prr2_ex1.asm
$ ld -m elf_i386 -o prr_ex1 prr2_ex1.o
We put a breakpoint on call store_eip
and on ret
using gdb.
We put a breakpoint on ret
using gdb
We start the program and read EIP:
image_todo
Then we read the content of EAX:
image_todo
They are both equal
1 - B) Why can’t you just do mov EAX, EIP ?
TODO
2) Come up with at least two code sequencies to set EIP to 0xAABBCCDD ?
Version A:
SECTION .data
SECTION .text
GLOBAL _start
_start:
mov eax, AABBCCDDh
call eax
Version B:
SECTION .data
SECTION .text
GLOBAL _start
_start:
jmp AABBCCDDh
3) In the example function ADDME, what would happen if the stack pointer were not properly restored before executing RET ?
TODO
4) In all of the calling conventions explained, the return value is stored in a 32-bit register (EAX). What happens when the return values 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 ?
TODO