4.3 KiB
title | date | tags | categories | |||||
---|---|---|---|---|---|---|---|---|
Sécurité logicielle : L'assembleur | 2023-01-20 |
|
|
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?
- le pré-processing : les fichiers inclus via les
#include
sont insérés dans le code source. - compilation en assembleur : les fichiers C obtenus précédemment sont traduits en assembleur
- compilation en langage machine : les fichiers obtenus précédemment sont traduits en langage machine
- é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 :
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.
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 :
t[i]++
Et son équivalent en assembleur :
addl1 $1, t(%eax,4)
addl
: mnémonique, ici add long$1
estt(%eax,4)
sont des opérandes$1
est une immédiat%eax
est un resgistret
est une référence, il pointe vers un endroit de la mémoire4
est un multiplicateur
On peu en déduire que t(%eax,4)
est une adresse mémoire.