Apprendre le hacking #6 // Un problème de mémoire

in #steemdev6 years ago

Apprendre le hacking 6.png

Sommaire

  • Présentation
  • La segmentation
  • La segmentation vue par GDB
  • Et en C ?

Présentation

Bonjour à tous et à toutes ! Que ce soit en informatique ou dans l'anatomie du cerveau humain, la mémoire nous réserves bien des suprises et est parfois bien compliquée à comprendre. Mais avec moi, le chemin vers le savoir suprême va s'éclaircir ! :D

Vous l'aurez donc bien compris, aujourd'hui, nous allons parler de la mémoire. Plus particulièrement la segmentation de la mémoire. C'est un point important puisque en tant que programmeur mais surtout en temps que hacker, vous devez être capable de savoir ou se trouve tel instruction ou tel variable. Nous verrons dans quelques semaines qu'il est fort pratique de savoir cela.

De quoi allez-vous avoir besoin ?

Pour suivre ce cours, vous allez avoir besoin d'avoir lu à minima les 2 premiers articles que vous mets ici : 1 | 2. A la suite de ceci vous aurez le bagage nécessaire pour comprendre comment fonctionnne un programme et ainsi savoir le décomposer en plusieurs parties avec un débogueur.

Pour comprendre mes codes vous devrez bien évidemment avoir lu tous les articles ! Ah ! J'oubliais, pour les tous nouveaux, sachez que les articles sont abordables même pour ceux que n'ont jamais touchés à un clavier. Pour vous, commencez à lire le tout premier article pour créer pour environnement de travail (votre machine virtuelle sous Linux).

Enfin, vous allez devoir créer un nouveau répertoire :

Capture.PNG

La segmentation

Nous avons à présent l'habitude de compiler nos programmes, nous savons aussi que en faisant cela, plusieurs zones mémoire s'ouvrent à nous. Aujourd'hui, nous allons voir que la mémoire est composée de 5 segments. Nous allons apprendre à jouer avec puisque chacun de ces segments à un rôle bien particulier.

Et quels sont ces segments ?

Oui, assez de suspens ! Nous avons donc le segment :

  • text ou en français, texte
  • data ou en français, données
  • bss
  • heap ou en français, tas
  • stack ou en français, pile

Je disais donc que chacun de ces segments à une fonctionnalité bien particulière. Prenons ceci dans l'ordre.

Text

Pour les programmeur plus expérimentés, vous connaissez sans doute ce segment sous la forme de : segment de code. Non ? Bon laissez-moi vous expliquer. Dans le segment de code se trouve toutes les instructions en langage machine de notre / nos programme(s). Nous ne pouvons pas écrire dans ce segment. On va dire alors qu'il est en lecture seule. En fait, si on essaie de le faire, le programme va nous avertir qu'il y a eu une grosse erreur et va tout simplement se stopper. Cela évite que quelqu'un modifie notre programme.

Il va être important de retenir que le contenu de ce segment ne change pas, il a donc une taille fixe.

Data

Ce segment sert de stockage aux variables globales (dans une autre fonction) mais aussi statiques d'un programme. Contrairement au segment de code ou segment text, nous pouvons écrire dans ce segment mais il a tout de même une taille fixe.

BSS

C'est ici identiquement la même chose que pour le Data. J'utilise cependant une partie différente car le bss concerne non pas les variables globales et statiques mais les variables non initialisées.

Heap

Celui-ci fera l'objet d'un prochain article puisque je vais avoir beaucoup de choses à en dire. En effet, ce segment a la particularité de pouvoir être manipulé par nous. Nous allons en effet pouvoir allouer des blocs de mémoire dans le heap et les utiliser.

Nous avons en un segment qui n'a pas de taille fixe. Ainsi nous avons la possibilité de le grandir ou le diminuer en fonction de ce que nous voulons faire avec.

Stack

A présent, le plus important de tous. La pile. Il a pour fonction de stocker les variables locales des fonctions mais aussi les appels de contexte des fonctions. En fait, lorsqu'un programme appelle une fonction, celle-ci a son propre ensemble de variable passées en arguments et son code se trouve dans le segment texte, dans un emplacement différent. La pile mémorise toutes les variables passées, l'emplacement sur lequel doit revenir RIP (le pointeur d'instruction) après avoir passé une fonction mais aussi toutes la variables locales de cette fonction. Et tout ceci réunis au même endroit : Le bloc d'activation.

La pile suis la procédure dite FILO (first-in, last-out). C'est à dire que le premier élément à rentrer et aussi le dernier à sortir. Quand on met sur la pile on push (empilement) quand en retire de la pile, on pop (dépilement).

La segmentation vue par GDB

Créons le programme suivant :

Capture.PNG

Dans le main on appel la fonction fonction qui prendre 4 entiers en paramètre (1, 2, 3, 4) d'où le int a, int b, int c, int d. Dans le code de laonction nous avons créé deux variables. Une de type int et contenant 326. Une deuxième de type char et contenant le caractère A. Si vous avez bien compris ce que j'ai dis précédement, vous êtes capables de dire où se trouvent les variables, dans quel segment. Mais aussi où se trouvent les instructions machine du code de la fonction.

Les variables, dans la pile et les instructions dans le segment texte ?

Oui tout à fait ! A présent, nous pouvons compiler notre programme et le regarder de plus près avec GDB.

Capture.PNG

Commençons d'abord par désassembler le main() mai aussi la fonction().

Capture.PNG
Capture.PNG

Dans ces deux captures nous pouvons voir que le main() et la fonction() ont au début un bloc d'activation. Pour le main il se termine avant le call et pour le fonction(), il se termine au sub avant le deuxième mov. Nous avions déjà parler de ces blocs d'activation au début de la série. J'avais dis que c'était en réalité le prologue de fonction. Aujourd'hui, nous pouvons y rajouter que ce prologue ou ces prologues sauvegardes notre pointeur de trame (RPB) sur la pile mais y réservent aussi de la mémoire pour les variables locales, que je mets en gras, de la fonction.

Nous pouvons voir que dans le désassemblage de main(), avant d'appeler la fonction, nous voyons que les arguments de fonction() sont dans l'ordre inverse. Ce n'est cependant pas une suprise puisque j'ai déjà prévenu de ce comportement FILO (first-in, last-out).

Capture.PNG

S'éxecute ensuite la fonction call, l'adresse de retour est placée (ici 0x00000000004005a8). En fait, l'adresse de retour c'est tout simplement après l'instruction que donne le RIP courant, donc après la fonction call ici. Enfin on saute au début de la fonction(). On peut voir que deux adresses sont identiques. L'instruction call stocke l'adresse de retour sur la pile et RIP se place au début du bloc d'activation de fonction().

Capture.PNG

Durant ce prologue, la valeur de RPB (le pointeur de base) est empilé sur la pile. On l'appel en réalité pointeur de bloc d'activation sauvergardé ou SFP pour saved frame pointer et va servir à remettre RPB dans son état d'origine. Le pointeur de pile (RSP) est ensuite copié dans dans RPB pour avoir le nouveau pointeur de base. Mais observons tout cela à l'aide de GDB.

Capture.PNG

On a placé les points d'arrêts avant l'appel à la fonction et au début de notre fonction. Donc GDB place le premier breakpoint avant l'empilement des arguments de fonction() et le second apres le prologue de fonction(). Nous choisissons d'afficher les valeurs du pointeur de pile, du pointeur de base et du pointeur d'instruction. Le premier breakpoint est donc juste avant le prologue de fonction() au pointeur de pile 0x7fffffffddeo.

Capture.PNG

En poursuivant l'éxecution, nous allons nous arrêter juste après la création du prologue de fonction().

Capture.PNG
Capture.PNG

Regardons un peu de plus près notre RSP :

Capture.PNG

Nous voyons que la première line possède les 4 arguemnts de la fonction et l'adresse de retour est donnée aussi avant le deux points.Essayez par vous-même de chercher le pointeur de bloc d'activation sauvegardé. Ici il est à l'adresse 0x7fffffffdde0 puisque c'est une copie de RBP. Une fois ceci terminé, la pile est dépilée et l'adresse de retour est donnée à RIP pour continuer l'exécution normale du programme. Un autre bloc d'activation sera placé sur la pile si jamais une autre fonction est appelée.

Sachez tout de fois que chez moi les adresses dites basses (comme les arguments des fonctions) sont placées en haut et les adresses basses en bas. Je ne sais pas si l'inverse se fait encore même si pour ma part c'était plus pratique ainsi et cela montrait bien le fonctionnement FILO.

Et en C ?

Dans tous les langages de programmation, le code compilé est placé dans le segment texte et les variables dans les autres segments. Oui en effet car ceci dépend de comment est construite la variable. Par exemple, et la revenons au C, les variables globales (en dehors des fonctions) et les variables statiques (écrites avec static), initialisées toutes deux avec des données sont de la segment data. Si elles ne sont pas initialisées, alors elles se trouverons dans le segment bss.

Il faut aussi savoir que la mémoire disponible dans le heap (tas) doit être allouée avec la fonction malloc() mais nous ferons un article sur cette fonction. Nous faisons les références à la mémoire plutôt avec les pointeurs. Enfin, les variables de fonctions restantes sont stockées dans le segment stack (pile) comme nous avons pus le voir.

Important : vous savez à présent que la pile peut avoir plusieurs bloc d'activation, c'est à dire que les variables qui s'y trouvent peuvent rester uniques à l'intérieur des différents contextes de fonctions.

Regardez cette exemple qui va illuster au mieux tout ceci :

Capture.PNG

Capture.PNG

Je pense que le code est assez simple à comprendre. Ne vous inquiétez par pour la fonction malloc(), nous allons avoir assez de temps pour en parler !

La semain prochaine nous allons apprendre à utiliser le tas (le segment heap). Ceci implique donc aussi les malloc() au prochain cours. En effet, pour allouer une zone mémoire sur le tas, nous devons utiliser la fonction malloc().




Hey ! J'éspère que cette série te plaîs ! N'hésite pas à me le dire en commentaire et aussi à me donner des conseils de rédaction, j'aime partager et apprendre des autres !

Tu peux aussi me suivre sur mes réseaux sociaux afin d'être informé de l'arrivé d'un nouvel article ou d'une nouvelle vidéo :


Sort:  

Un autre excellent cours exercé par vos soins ! Upvoté à 100% !

Merci beaucoup !

Ce post de qualité a été découvert par l'équipe OCD francophone (@roxane,@ixindamix et @kaliangel ) !

Répondez à ce commentaire si vous acceptez, et si vous nous accordez le droit de nous laisser partager votre article en utilisant la mention : "J'accepte". En acceptant ceci, vous avez une chance de recevoir des récompenses supplémentaires et l'une de vos photos dans cet article peut être utilisée dans notre article récapitulatif !

Vous pouvez suivre @ocd pour en savoir plus sur le projet et voir d'autres perles ! Nous visons la clarté et la transparence.

Coin Marketplace

STEEM 0.27
TRX 0.11
JST 0.030
BTC 68362.67
ETH 3798.22
USDT 1.00
SBD 3.49