cours/content/secu_logicielle/3_assembleur_approfondissement/index.md

284 lines
8.6 KiB
Markdown

---
title: "Sécurité logicielle : L'assembleur - approfondissement"
date: 2023-02-01
tags: ["assembleur", "intel"]
categories: ["Sécurité logicielle", "Cours"]
---
## Un premier exemple
Prenons `IP` comme compteur et `A` , `B`, `C` et `D` comme registres.
```asm {linenos=true}
0x00: mov $1, A
0x05: mov $2, B
0x0a: mov $3, C
0x0f: add A, B
0x10: cmp B, C
0x11: jz zero
0x12: mov $41, A
0x17: jmp end
0x18: zero:
0x18: mov $42, A
0x1d: end:
```
La première colonne représente le compteur d'instruction, nous pouvons vois que
chaque *instruction prend 5 octets*.
Ligne 4, la seconde opérande de l'instruction `add` est aussi le résultat
Ligne 5, l'instruction `cmp` fait une comparaison, en fait il fait une
soustraction des deux opérandes. Si le résultat de cette sourtraction (et dons
que les opérandes sont égales) alors l'instruction `jz` (*jump zero*) réalisera
un saut vers l'étiquette `zero`.
## Le langage
### Les registres
Il étaient de 8 bits à l'origine et nommés `A`, `B`, `C` et `D`, lors du passage
en 16 bits, ils se sont appelés `Ax`, `Bx`, `Cx`, `Dx` (pour *extended*). Lors
du passage à 32 bits ils sont passé à `eAx`, `eBx`, `eCx`et `'eDx`. Enfin ils
sont passé à `rAx`, `rBx`, `rCx` et `rDx` pour la version 64 bits.
Lors de ce cours, nous utiliseront principalement les versions 32 bits.
### Les suffixes d'instructions
Toute comme pour les registres, il existe des version de certaines instructins
en fonction de la taille des opérandes :
* `movb` : 8bits
* `movb` : 16 bits
* `movl` : 32 bits
* `movq` : 64 bits
### Les usages
Il existe plusieurs type de registres en fonction de leur usage
* registres **généraux** : `rAx`, `rBx`, ...
* registres **d'indexation** : `RSI` (source) et `RDI` (destination)
* registres supplémentaire 64 bits : de `R8` à `R15`
Nous en verrons d''autre un peu plus tard.
### Flags de résultats
C'est un registre de 32 bits, chaque bit correspond à un drapeau spécifique :
Les 16 premier bits repente les *flags* :
position | flag | fonction
---------|------|----------
0 | CF | Carry flag
2 | PF | Parity flag
4 | AF | Adjust flag
6 | ZF | Zero flag (si le résultat est 0)
7 | SF | Sign flag (valeur de bit de poids fort)
8 | TF | Trap flag
9 | IF | Interrupt enable flag
10 | DF | Direction flag (sens de lecture d'une chaine de caractère)
11 | OF | Overflow flag (positionné en cas d'overflow)
12 13| IOPL | IO privilege number
14 | NT | Nested tag flag
Et les 16 suivants les *eflags*:
position | flag | fonction
---------|------|----------
16 | RF | Resume flag (Défini la réponse CPU pour la reprise à l'exception pour
debug)
17 | VM | Virtual 8086 mode
18 | AC | Alignement check
19 | VIF | Virtual interrupt flag
20 | ID | CPUID flag (possibilité d'utiliser le CPUID)
21-31 | Réservé
### Les instructions
#### Addition / soustraction / incrémentation / décrémentation
* `add <src> <dest>` : addition de `<src>` et `<dst>`, positionnement du
résultat dans `<dst>`
* `sub <src> <dst>` : soustraction de `<src>` et `<dst>`, positionnement du
résultat dans `<dst>`
* `inc <val>` : incrémenter `<val>`
* `dec <val>` : décrémenter `<val>`
* `neg <val>` : renvoie le complément à deux de `<val>`
```asm
movl $20 %rax # rax = 15
addl $10 %rax # rax = rax + 10 = 25
subl $7 %rax # rax = rax - 7 = 18
incl %rax # rax += 1 = 19
decl %rax # rax -= 1 = 19
```
#### Division / Multiplication
* `mul <src>` : multiplication de `%eax` par `<src>`, `%eax` est choisi en dur,
le résultat est écrit sur deux registres `%edx` et `%eax`. `mul` retroune un
résultat **non signé**.
* `imul` : multiplication comme précédement, mais le résultat est cette fois
**signé**
* `div <dst>` : divise le nombre contenu dans `%eax` et `%edx` par `<dst>`. Le
quotien sera positionné dans `%eax` et le reste dans `%edx`. Le résultat est
**non signé**.
* `idiv <dst>` : division comme précédement mais cette fois le résultat est
**signé**.
```asm
movl $0 %edx
movl $8 %eax
movl $2 %ebx
divl %ebx # %eax = %edx.%eax / %ebx remainer : %edx
movl $0 %edx
movl $8 %eax
movl $2 %ebx
mull %ebx # %eax = %ebx * %eax
```
#### Shift, rotate
On parle ici de décalage de bits que se soir à gauche (multilication par 2
puissance X) ou à droite (division par 2 puissance X).
* `shl <n> <dst>` : décalage à gauche de `<dst>` de `<n>` bits (`<dst> << n`).
* `shr <n> <dst>` : décalage à droite de `<dst>` de `<n>` bits (`<dst> >> n`).
Ces deux instructions sont **non signées**, les versions **signées** sont `sal`
et `sar`.
* `sol <n> <dst>` : applique une rotation de `n` bits vers la gauche de `<dst>`
* `sor <n> <dst>` : applique une rotation de `n` bits vers la droite de `<dst>`
```asm
movl $0xa %eax
rol $0x2 %eax # 00001010 -> 00101000 = 0x28
```
#### Opération bit à bit
* `and <src> <dst>` : réalisation de l'opération `<src> & <dst>`,
positionnement de résultat dans `<dst>`
* `or <src> <dst>` : réalisation de l'opėration `<src> | <dst>`, positinnement
du résultat dans `<dst>`
* `xor <src> <dst>` : réalisation de l'opėration `<src> ^ <dst>`, positinnement
du résultat dans `<dst>`
* `not <dst>` : réalisation de l'opération `<~dst>` et poitionnement du résultat
dans `<dst>`
* `cmp <1> <2>` : réalisation de l'opération `<1> - <2>`, le résultat n'est pas
affecté mais les drapeaux OF, ZF AF, CF PF son positionné en fonction du
résultat.
#### Instruction de branchement
Certaines de ces instructions on plusieurs notations possibles.
* `jmp <addr>` : saut vers l'adresse `<addr>` sans condition
* `ja <addr>` : saut vers l'adresse `<addr>` si la comparaison au dessus donne
comme résultat *strictement supérieur à*
* `jae <addr>` : saut vers l'adresse `<addr>` si la comparaison au dessus donne
comme résultat *supérieur ou égal à*
* `jnae <addr>` : saut vers l'adresse `<addr>` si la comparaison au dessus donne
comme résultat *strictement inférieur à* (not above or equal) -- peut être
aussi `jng` (not greater)
* `jz <addr>` : saut vers l'adresse `<addr>` si la comparaison au dessus donne
comme résultat *égal à*
#### Instruction diverses
* `loop <addr>`: décrémente `%ecx` et effectue un saut vers `<addr>` si `%ecx`
et supérieur à 0.
* `loope <addr>`: décrémente `%ecx` et effectue un saut vers `<addr>` si `%ecx`
et supérieur à 0 et `ZF` = 1. Peut aussi être nommé `loopz`
* `loopne <addr>`: décrémente `%ecx` et effectue un saut vers `<addr>` si `%ecx`
et supérieur à 0 et `ZF` = 0. Peut aussi être nommé `loopnz`
* `noop`: ne fait rien...
### Gestion de la Mémoire
Nous avons différents types d'opérandes pour la mémoire. que se soit sur les
registres :
```asm
# affecter le contenu de %eax dans %ebx
movl %eax %ebx
```
Pour les immediats:
```asm
# Affecter 1 à %ebx
movl $1 %ebx
# Affecter 0xa à %ebx
movl $0xa %ebx
# Affecter l'adresse `a` à %ebx
movl $a %ebx
```
Et pour l'acces direct à la mémoire
```asm
# Erreur !!
movl a %ebx
# Référence à l'adresse `a`
movl $a %ebx
```
Et enfin les accès indirects à la mémoire. Le principe ici est base + index *
type + déplacement. Si le type est omit alors il vaut 1 si le déplacement est
omis il vaut 0. Concrètement l'adresse est organisée comme suit:
`<deplacement>(<base>, <index>, <type>)`
```asm
# Copie le contenu de la case mémoire pointé par le contenu de %ebx dans %eax
movl (%ebx) %eax
# Copie le contenu à l'adresse %ebx + 4 octets dans %eax
movl 4(%ebx) %eax
# Cette fois c'est le contenu à l'adresse %ebx - 4
movl -4(%ebx) %eax
# le contenu à l'adresse %ecx + %ebx
movl (%ebx, %ecx) %eax
# contenu à l'adresse %ebx +t
movl t(%ebx) %eax
# contenu à l'adresse t + %ebx + %ecx * 4
movl t(%ebx, %ecx, 4) %eax
```
#### Move, xchg, lea
Ces instructions servent à copier une valeur d'un endroit (registre, mémoire ) à
un autre.
* `movl <src> <dst>` : copie le contenu de `<src>` vers `<dst>`, `<src>` peut
être une constante, un registre ou un adresse (label) et `<dst>` une adresse
ou un registre.
* `xchg <a> <b>` : ;echange le contenu de `<a>` et de `<b>`
* `leal <src> <dst>` : calcule l'adresse source (`<src>`) et place le résultat
dans `<dst>`. Contrairement à `movl`, `leal` ne traite pas la valeur mais
bien **l'adresse**
Il est possible d'utiliser `leal` pour effectuer des calculs arithmétiques non
signé. Ainsi on peut bénéficier d'un avantage : **les drapeaux ne sont pas
impactés**.
* `cmov<cmp> <src> <dst>`: copie `<src>` vers `<dst>` en fonction de
l'instruction de comparaison précédente et de l'instruction donnée par
`<cmp>`.
```asm
cmpl %eax %ebx # %ebx - %eax
cmovgel $1 %edx # si %ebx > ebx (res > 0) alors %edx = 1
```