125 lines
4.3 KiB
Markdown
125 lines
4.3 KiB
Markdown
---
|
|
title: "Sécurité logicielle : L'assembleur"
|
|
date: 2023-01-20
|
|
tags: ["programmation", "intel", "processeur"]
|
|
categories: ["Sécurité logicielle", "Cours"]
|
|
---
|
|
|
|
Il existe plusieurs niveau de langages:
|
|
|
|
* langage de **haut niveau** : no-code, python, Java, ce sont des langages
|
|
souvent interprété ou le développeur ne gère pas le matériel (typiquement la
|
|
mémoire et contenant des objets abstrais ( lambda, liste, objet).
|
|
* langages de **bas niveau** : comme le C, le développeur manipule la mémoire
|
|
(pointeurs, allocation et libération de la mémoire)
|
|
* **assembleur** : on se rapproche un peu plus du matériel, notamment du
|
|
processeur en manipulant instruction et registres, mais le tout reste lisible
|
|
par un humain
|
|
* **code machine** : ici nous avons que du binaire, *"à même le proce'"*
|
|
|
|
L'*assembleur* et le *langage machine* sont deux manières différentes de
|
|
**représenter la même chose**.
|
|
|
|
## La compilation
|
|
|
|
Que se passe-t-il lors du passage d'un programme en C en code machine?
|
|
|
|
1. **le pré-processing** : les fichiers inclus via les `#include` sont insérés
|
|
dans le code source.
|
|
2. **compilation en assembleur** : les fichiers C obtenus précédemment sont
|
|
traduits en *assembleur*
|
|
3. **compilation en langage machine** : les fichiers obtenus précédemment sont
|
|
traduits en langage machine
|
|
4. *édition des liens* : le code obtenu est alors lié avec les bibliothèques
|
|
externes, il deviens **un vrai programme**.
|
|
|
|
Sous Linux, un programme est chargé automatiquement avec `ld-linux`. Lors du
|
|
chargement d'un programme **setuid** (qui peut obtenir les droits root),
|
|
`ld-linux` ne prend pas en compte les variable d'environnement `LD_LIBRARY_PATH`
|
|
et `LD_PRELOAD` afin d'éviter tout risque pour la sécurité.
|
|
|
|
### Problèmes potentiels sur ces étapes
|
|
|
|
Pour l'étape 1, il n'y a en général pas de problèmes, cependant **certaines
|
|
macros** peuvent poser problèmes.
|
|
|
|
Pour l'étape 2, le problème pourrait venir du *"mensonge"* fait par le
|
|
compilateur lors de la traduction du C vers l'assembleur, ou encore l'interface
|
|
chaise clavier lors de l'écriture du programme.
|
|
|
|
Pour l'étape 3, pas de problème, c'est ici une simple traduction littérale
|
|
|
|
Pour l'étape 4, il peut arriver quelques trucs horrible, typiquement des
|
|
**conflits de symboles** lorsque le programme et une librairie ont un nom de
|
|
variable (globale) en commun.
|
|
|
|
Lors de l'exécution, il est possible d'utiliser `LD_LIBRARY_PATH` et
|
|
`LD_PRELOAD` pour détourner des bibliothèques utilisées.
|
|
|
|
## L'assembleur
|
|
|
|
C'est un langage élémentaire, très verbeux et fastidieux. Mais parfois c'est le
|
|
seul moyen de voir **ce qui se passe réellement**. Prenons cet exemple en C :
|
|
|
|
```c
|
|
unsigned x = 0;
|
|
while (x < -1) {
|
|
printf("ok\n");
|
|
}
|
|
```
|
|
|
|
Ici nous allons entrer dans une boucle infinie, la faute au *cast* de `x`
|
|
(`unsigned int` vers `int`).
|
|
|
|
### Qu'est-ce que l'assembleur?
|
|
|
|
C'est le cœur du calcul, entre la machine de Turing (mais en moins complexée) et
|
|
l'architecture de [Von Neumann][l_vonneumann].
|
|
|
|
C'est un langage non structuré avec des **instructions arithmétiques simples** :
|
|
|
|
* lecture / écritures dans la mémoire
|
|
* opération de saut
|
|
* test (if)
|
|
* pas d'appel de fonctions
|
|
* pas de scope
|
|
|
|
Les commentaires sont essentiels afin de marquer les points essentiels du code
|
|
(début de test, branchement) et le rendre pus intelligible.
|
|
|
|
### Un peu d'histoire
|
|
|
|
* 1971: *Intel* commercialise le 4004 cadencé à 740 Khz et avec 640 bits de
|
|
mémoire
|
|
* 1972: *Intel* commercialise le 8008, registres de 8bits et 800Khz de
|
|
fréquence
|
|
* 1978: *Intel* commercialise le 8086 avec des registres de 16 bits et cadancé
|
|
jusqu'à 10 Mhz.
|
|
* 1985: *Intel* commercialise le 386 aved des registres de 32 bits et 4Go de
|
|
mémoire adressable. Ce processeur introduit la mémoire virtuelle.
|
|
* 1997: *Intel* commercialise le Pentium
|
|
|
|
### Un peu de vocabulaire
|
|
|
|
Voici un code en C :
|
|
|
|
```c
|
|
t[i]++
|
|
```
|
|
|
|
Et son équivalent en assembleur :
|
|
|
|
```asm
|
|
addl1 $1, t(%eax,4)
|
|
```
|
|
|
|
* `addl` : mnémonique, ici *add long*
|
|
* `$1` est `t(%eax,4)` sont des opérandes
|
|
* `$1` est une immédiat
|
|
* `%eax` est un resgistre
|
|
* `t` est une référence, il pointe vers un endroit de la mémoire
|
|
* `4` est un multiplicateur
|
|
|
|
On peu en déduire que `t(%eax,4)` est une **adresse mémoire**.
|
|
|
|
[l_vonneumann]:https://fr.wikipedia.org/wiki/Architecture_de_von_Neumann
|