111 lines
2.8 KiB
Markdown
111 lines
2.8 KiB
Markdown
---
|
|
title: "Sécurité logicielle : L'assembleur - appel de fonction"
|
|
date: 2023-02-10
|
|
tags: ["assembleur", "intel", "mémoire"]
|
|
categories: ["Sécurité logicielle", "Cours"]
|
|
---
|
|
|
|
L'instruction poour l'appel de fonction est `call`, elle est équivalent un
|
|
|
|
|
|
```asm
|
|
pushl %eip+5
|
|
jump f
|
|
```
|
|
|
|
On sauvegarde l'adresse de retour sur la pile et un effectue un saut dans le
|
|
code. Lors du retour, nous effetuerons alors :
|
|
|
|
```
|
|
popl %eip
|
|
jumpl (%esp)
|
|
addl $4 %esp
|
|
```
|
|
|
|
## Passage de paramètres (en 32 bits)
|
|
|
|
Le passage de paramètre n'est pas spécifié dans la dosumentation des processeur,
|
|
mais dans une documentation à part et relative à chaque systèmes (Linux, MacOS,
|
|
FreeBSD, OpenBSD, etc.)
|
|
|
|
Prenons l'exemple de la fonction `x=f(42, 52)` :
|
|
|
|
```asm
|
|
pushl $52 # on commence par le paramètre le plus à droite
|
|
pushl $42
|
|
call f
|
|
```
|
|
N'oublions pas que lors de lappel de fonction, l'adresse de retour est
|
|
positionnée sur la pile, vous avons donc:
|
|
|
|
|adresse|contenu|
|
|
|----|----|
|
|
|0xff| 52 |
|
|
|0xfb| 42 |
|
|
|0xf8| retour|
|
|
|
|
Voici maintenant le code de notre fonction :
|
|
|
|
```asm
|
|
f:
|
|
movl 4(%esp) %eax # Attendre l'adresse 0xfb
|
|
addl 8(%esp) %eax
|
|
ret # retour de notre fonction, résultat dans eax
|
|
```
|
|
|
|
Il faut penser à netoyyer la pile **dans la fonction appelante**
|
|
## Les variables locales
|
|
|
|
Elle se positionnent sur la pile après l'adresse de retour. Il faudra bien
|
|
évidement le prendre en compte lors du calcul du décalage lors del
|
|
accès au paramètres:
|
|
|
|
|adresse|contenu|
|
|
|----|----|
|
|
|0xf0| 52 |
|
|
|0xfc| 42 |
|
|
|0xf8| retour|
|
|
|0xf4| 94|
|
|
|
|
```asm
|
|
f:
|
|
subl $4, %esp
|
|
movl 8(%esp), %eax # Attendre l'adresse 0xfb
|
|
addl 12(%esp), %eax
|
|
movl %eax, (%esp)
|
|
...
|
|
addl $4, %esp
|
|
ret # retour de notre fonction, résultat dans eax
|
|
|
|
```
|
|
|
|
## Le Base Pointer
|
|
|
|
Lors de l'entrée dans une fonction, nous sauvegardons l'adresse contenue dans
|
|
`ebp` sur la pile puis on copie l'adresse contenue dans `esp` dans `epb`,
|
|
|
|
```asm
|
|
f:
|
|
pushl %ebp ; on sauvegarde l'adresse contenue dans %ebp sur la pile
|
|
movl %esp, %ebp ; puis copier l'adresse courante d'%esp dans %ebp
|
|
```
|
|
|
|
Sur l'architecture x86, ces deux instructions peuvent être remplacées par le
|
|
mnémonique `enter`.
|
|
|
|
Il nous est mainteant possible de retrouver simplement les paramètres passées à
|
|
notre fonction par rapport à `ebp` tout en instanciant des variables locales sur
|
|
la pile que nous retrouverons en fonction d'`esp`. **C'est à la fonction appelée
|
|
de mettre en place le *base pointer***
|
|
|
|
À la fin de notre fonction, nous allons positionner le retour dans `%eax` et
|
|
remettre les choses en places:
|
|
|
|
```asm
|
|
;[...]
|
|
movl -4(%ebp), %eax ; on met notre valeur de retour dans %eax
|
|
movl %ebp, %esp ; on restaure %esp
|
|
popl %ebp ; on pop le haut de la pile dans %ebp on restaure ainsi
|
|
; sa valeur avant l'appel de notre fonction
|
|
ret
|
|
```
|