Dépassement mémoire

Vous avez peut-être déjà entendu parler de certains programmes qui pouvaient planter ou encore être exploités en écrivant de longues chaînes de caractères. Il y a eu par exemple des noms de fichiers de plus de 256 caractères qui faisaient planter Explorer dans le temps de Windows 95 juste en navigant dans un répertoire avec ce genre de fichiers. Ou encore l’écriture d’un très long URL pour faire faire des choses douteuses à des scripts Web. Tous ces problèmes sont reliés au même problème de design qui permet le dépassement de mémoire.

Pour aller au vif du sujet, voici un exemple de programme qui a ce problème. J’ai inclus le code source à l’intérieur.

Dépassement de mémoire

En exécutant ce programme, vous allez voir la page suivante apparaître:

Memory adresses
Command: 0012FF58
User: 0012FF64

User:noob Command:
Next command >

Je vais expliquer plus tard chaque ligne. Pour l’instant, le programme demande une commande alors écrivez par exemple: « show ».

Next command > show
User:noob Command: show

Maintenant, écrivez 123456789012root .

Next command > 123456789012root
User:root Command: 123456789012root

Vous voyez le nom d’utilisateur changer. Dans ce programme, cela ne fait rien, mais dans un shell unix par exemple, cela voudrait dire que l’utilisateur a maintenant les privilèges du compte « root » et donc les privilèges administrateur.

Voici maintenant l’explication. Dans la première section, les adresses des variables « user » et « command » sont affichées. Il faut savoir qu’en C++, une variable qui est un tableau garanti seulement que dans la mémoire, il va y avoir l’espace suffisant pour pouvoir remplir le tableau de façon continu, mais si nous écrivons plus de valeurs que le tableau peut en prendre, l’écriture ne s’arrêtera pas d’elle-même. C’est pourquoi il a été possible d’écrire dans la variable « user » à partir de la variable « command ». Voici de quoi la mémoire à l’air dans cet exemple:
État Mémoire

Et pour terminer, un blitz de questions-réponses:

  • Pourquoi la dernière commande a-t-elle affichée tous les caractères et non juste les 10 premiers? Parce que comme dit précédemment, C++ ne gère pas les grandeurs des tableaux. Donc la seule façon pour savoir quand s’arrêter d’afficher des caractères c’est d’afficher des caractères tant que le caractère « null » n’est pas atteint. C’est pourquoi nous parlons souvent de « null terminated string ».
  • Est-ce que l’ordre des déclarations de variables dans le code source change la position dans la mémoire? Oui et non. La position dans la mémoire dépend de beaucoup de facteurs. C’est le compilateur qui décidera de l’ordre des variables selon l’optimisation choisie. Il y a aussi la position dans le code source du premier appel d’une variable qui peut modifier la position dans la mémoire. Le meilleur exemple est que ce code source, lorsque qu’il est compilé en mode « Release » dans Visual Studio 2008, les variables sont inversées dans la mémoire. C’est pourquoi je vous ai laissé le programme compilé en mode « Debug ».
  • Les adresses mémoire sont bizarres… Elles ne sont pas en base 10 (décimales), mais en base 16 (hexadécimales). Au lieu d’avoir les 10 chiffres 0 1 2 3 4 5 6 7 8 9, nous avons les 16 symboles 0 1 2 3 4 5 6 7 8 9 A B C D E F.