IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Adresse et taille d'un tableau statique


Sujet :

C

  1. #1
    Membre Expert
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Par défaut Adresse et taille d'un tableau statique
    Bonjour,

    Je cherche un moyen de récupérer la taille d'un tableau statique déclarée comme cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    int foo(char* buffer /* char buffer[1024] */)
    {
       // Affiche 4 la taille du pointeur mais je voudrais en fait récupérer 1024
       printf("sizeof(buf) = %d\n", sizeof(buf));
    }
    int main()
    { 
        char buffer[1024];
     
        // Affiche bien 1024
        printf("sizeof(buf) = %d\n", sizeof(buffer));
     
        foo(buffer);
     
        ...
    }
    Question 1 : Peux t-on récupérer la taille du buffer sans passer la taille en paramètre à la fonction foo ?
    Question 2 : Où est stocké l'adresse et la taille de buffer ? Dans le fichier objet, le fichier binaire ou alors déterminé au runtime ? De manière à pouvoir la récupérer quelque part...

    En fait, je voudrais savoir si les adresses (et leur taille dans mon exemple 1024) des tableaux statiques sont stockées dans le fichier main.o ou alors dans le binaire final main.exe ?

    Je travaille sous Windows 7, je sais que chaque programme dispose d'un espace de mémoire virtuelle, mais je ne sais pas trop comment cela marche.

    Merci d'avance et bonne journée
    Qui ne tente rien n'a rien !
    Ce qui ne nous tue pas nous rends plus fort !!
    Mon projet ZELDA en C++/Allegro
    http://www.tutoworld.com - Le Forum -
    Mes ressources Dotnet (cours, sources, tutos)
    --------------------------------------------
    + + =

    Ne pas oublier le Tag !

  2. #2
    Membre très actif

    Femme Profil pro
    Collégien
    Inscrit en
    Juillet 2010
    Messages
    607
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : Afghanistan

    Informations professionnelles :
    Activité : Collégien

    Informations forums :
    Inscription : Juillet 2010
    Messages : 607
    Par défaut
    Bonjour,

    Question 1 : Peux t-on récupérer la taille du buffer sans passer la taille en paramètre à la fonction foo ?
    Non

    Question 2 : Où est stocké l'adresse et la taille de buffer ?
    Null part elle est juste connue à la compilation, dans cas de buffer[1024]
    Sinon l’adresse est renvoyée par malloc dans le cas d'une allocation dynamique du tableau

    De manière à pouvoir la récupérer quelque part...
    buffer est l'adresse de début du tableau
    printf("0x%p\n",buffer);

  3. #3
    Membre Expert
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Par défaut
    D'accord

    Null part elle est juste connue à la compilation, dans cas de buffer[1024]
    Et justement, est-il possible de la récupérer ? (soit pendant le processus de compilation ou alors dans un fichier intermédiaire ?)

    Pour les allocations dynamiques, je n'ai aucun problème puisque je peux surcharger la fonction malloc et récupérer toutes les infos que je veux (adresse et taille notamment) mais pour les tableaux statiques, c'est plus compliqué...

    En fait le but serait de faire une map des tableaux statiques présent dans un fichier source .C en disant :
    buffer => adresse 0x0000ABCD, taille = 1024
    buffer2 => adresse 0x0000BBBB, taille = 128
    ...


    afin de détecter d'éventuels buffer overflow/underflow sur des buffers statiques (je sais qu'il existe des outils pour cela mais je voudrais comprendre par moi même et me créer mon propre outil). Etant donné que CPPcheck le fais déjà, il doit bien y avoir une solution pour savoir à l'avance les adresses et tailles des tableaux statiques non ?

    Merci
    Qui ne tente rien n'a rien !
    Ce qui ne nous tue pas nous rends plus fort !!
    Mon projet ZELDA en C++/Allegro
    http://www.tutoworld.com - Le Forum -
    Mes ressources Dotnet (cours, sources, tutos)
    --------------------------------------------
    + + =

    Ne pas oublier le Tag !

  4. #4
    Membre très actif

    Femme Profil pro
    Collégien
    Inscrit en
    Juillet 2010
    Messages
    607
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : Afghanistan

    Informations professionnelles :
    Activité : Collégien

    Informations forums :
    Inscription : Juillet 2010
    Messages : 607
    Par défaut
    buffer => adresse 0x0000ABCD, taille = 1024
    buffer2 => adresse 0x0000BBBB, taille = 128
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    printf("buffer => adresse 0x%p, taille = %d\n,"buffer,BUFFER_SIZE);
    printf("buffer2 => adresse 0x%p, taille = %d\n,"buffer2,BUFFER2_SIZE);
    En fait quand je dis que l'adresse st stockée null part, quelque part c'est faux.
    buffer est l'adresse du tableau nommé buffer.
    Mais quand tu fais printf("buffer:0x%p\n",buffer), le compilo remplace buffer par une constante connue à la compilation.
    Cette constante est stockée nulle part, mais cela ne veut pas dire que tu ne peux pas connaitre sa valeur.
    Si vraiment tu veux une variable rien ne t’empêche de faire char *const addresse_de_buffer = buffer;

  5. #5
    Membre chevronné
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Par défaut
    En fait quand tu declares un tableau sur la stack, tu ne fais que ajouter a la taille reservee pour la stack frame. Mais c'est la somme totale de la taille des variables qui est reservee.

    Par exemple, sur 32 bits, si tu as:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    int a;
    int b;
    char buf[1024]
    le compilo va reserver le tout en prologue de fonction:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    mov ebp, esp
    sub esp, 0x408
    ou 0x408 est egal 1024 + sizeof(int) + sizeof(int). Je simplifie car ce chiffre varie en fonction du padding/alignement introduit par le compilo, ainsi que des valeurs utiles pour depiler la stack (saved ebp, saved eip).

    Donc en gros au runtime, tu ne peux pas savoir en examinent simplement la stack quelle est la taille de ton tableau. Tu as seulement la taille totale occupee par les variables locales.

    Citation Envoyé par Aspic Voir le message
    Et justement, est-il possible de la récupérer ? (soit pendant le processus de compilation ou alors dans un fichier intermédiaire ?)
    A la pre-compilation ou avant la compilation c'est possible. Je sais pas exactement comment. C'est exactement ce que fait FORTIFY_SOURCE sur gcc. Il analyse le code source ou intermediaire, determine la taille des tableaux et reordonne la declaration des variables. Les tableaux sont positionnes au dessus des variables locales, pour eviter qu'en cas d'overflow on puisse ecraser une variable locale. La protection de saved eip est laisse au canari introduit par stack-protector.
    Ces deux fonctionnalites permettent de specifier la taille du tableau a proteger, donc doivent parser le code/IL avant compilation.

    Citation Envoyé par Aspic Voir le message
    afin de détecter d'éventuels buffer overflow/underflow sur des buffers statiques (je sais qu'il existe des outils pour cela mais je voudrais comprendre par moi même et me créer mon propre outil).
    Pour cppcheck, c'est de l'analyse statique, donc c'est facile.
    Pour avoir une solution de protection au runtime, il faut introduire un hook au niveau de la pre-compilation.

    Bon courage.

  6. #6
    Membre Expert
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Par défaut
    Tout d'abord, merci pour vos réponses.
    Donc en gros au runtime, tu ne peux pas savoir en examinent simplement la stack quelle est la taille de ton tableau. Tu as seulement la taille totale occupee par les variables locales.
    Par curiosité, comment peut-on récupérer en C la taille totale des variables allouées sur la stack ? Qui sait, cela pourra peut être me servir pour détecter un éventuel dépassement de stack.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    #define sprintf(buf, ....) sprintf_check((buf), ....)
     
    int sprintf_check(char* buf, ....)
    {
        // Je peux intercepter l'appel à cette fonction mais comment vérifier ce type d'overflow ?
        // Je peux avoir son adresse mais pas la taille réelle car sizeof ne fonctionne pas, il me donnera la taille du pointeur...
        printf("0x%p\n", buf);
     
    }
     
    void foo(char* buf)
    {
        sprintf(buf, "%s", "je vais faire un overflow !!");
    }
     
    int main()
    {
        char b[2];
        foo(b);
    }
    Ok donc dans ce cas, y'a t-il un moyen de détecter ce genre d'overflow ? Puisqu'il est impossible de connaitre la vraie taille du buffer dans la fonction foo, comment faire ?

    PS : Je suis sur que Cppcheck ne peut pas vérifier ce genre de problème avec une simple analyse statique.
    Qui ne tente rien n'a rien !
    Ce qui ne nous tue pas nous rends plus fort !!
    Mon projet ZELDA en C++/Allegro
    http://www.tutoworld.com - Le Forum -
    Mes ressources Dotnet (cours, sources, tutos)
    --------------------------------------------
    + + =

    Ne pas oublier le Tag !

  7. #7
    Membre chevronné
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Par défaut
    Citation Envoyé par Aspic Voir le message
    Par curiosité, comment peut-on récupérer en C la taille totale des variables allouées sur la stack ? Qui sait, cela pourra peut être me servir pour détecter un éventuel dépassement de stack.
    Je peux parler que de Linux ici, avec gcc et convention cdecl. Tu peux inliner de l'asm. Pour 32 bits, si tu fais un truc du genre:
    Code asm : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    push eax
    pushfd
    mov eax, ebp
    sub eax, esp    ; ici eax contient vaguement la taille de ta stack frame
    popfd
    pop eax

    Tu as une taille approximative:
    1. Alignee sur 4 bytes ou 8 bytes (32/64 bits), donc du padding compilo
    2. Dependant de la sauvegarde des registres en prologue de fonction. Si tu as un pushad, tu decales ta stack d'autant


    Citation Envoyé par Aspic Voir le message
    Ok donc dans ce cas, y'a t-il un moyen de détecter ce genre d'overflow ? Puisqu'il est impossible de connaitre la vraie taille du buffer dans la fonction foo, comment faire ?
    Bah tu peux pas a ma connaissance. C'est pour ca que les protections se font a la compilation, ou en imposant l'utilisant des fonctions consideres safes (snprintf, ...).

    Citation Envoyé par Aspic Voir le message
    PS : Je suis sur que Cppcheck ne peut pas vérifier ce genre de problème avec une simple analyse statique.
    Pourquoi? Toutes les tailles sont connues ici: b => 2 bytes, cste "je vais faire un overflow !!" => 28 bytes. C'est assez simple pour analyseur statique de trouver ce genre de probleme dans des cas simples comme ca.

  8. #8
    Membre Expert
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Par défaut
    Citation Envoyé par dahtah Voir le message
    Je peux parler que de Linux ici, avec gcc et convention cdecl. Tu peux inliner de l'asm. Pour 32 bits, si tu fais un truc du genre:
    D'accord, merci je vais voir si sous Windows, il y a un équivalent.
    Citation Envoyé par dahtah Voir le message
    C'est pour ca que les protections se font a la compilation [...]
    Qu'est ce que tu entends par là ?
    Qui ne tente rien n'a rien !
    Ce qui ne nous tue pas nous rends plus fort !!
    Mon projet ZELDA en C++/Allegro
    http://www.tutoworld.com - Le Forum -
    Mes ressources Dotnet (cours, sources, tutos)
    --------------------------------------------
    + + =

    Ne pas oublier le Tag !

  9. #9
    Membre chevronné
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Par défaut
    Citation Envoyé par Aspic Voir le message
    D'accord, merci je vais voir si sous Windows, il y a un équivalent.
    Le meme ASM doit marcher sous Windows qui semble utiliser stdcall (qui est identique a cdecl, mis a part la liberation de la frame). Si le compilateur que tu utilises te permet de faire de l'ASM inline, ca devrait marcher.

    Citation Envoyé par Aspic Voir le message
    Qu'est ce que tu entends par là ?
    Que verifier la taille d'un tableau statique au runtime est impossible. cf ce que j'ai dit precedement sur FORTIFY_SOURCE. Si tu regardes le lien, tu verras que FORTIFY_SOURCE passe la taille du tableau a une variante safe de strcpy(). Comment est-ce que la taille du tableau est determine? Avant la compilation, par analyse du code source ou de l'IL genere par GCC.

  10. #10
    Membre Expert
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Par défaut
    Merci pour le lien, j'ai appris pas mal de chose notamment la notion de "Canary" pour protéger contre les buffer overflow de la stack.
    Je me demandais s'il y avait un moyen d'implémenter une version simple du canari en C ? Après avoir fait pas mal de tests, j'ai compris que le compilateur changeait de place les déclarations de variable en mettant les tableaux statiques en premier puis les types scalaires en dernier juste avant l’adresse de retour. De plus, j'ai remarqué qu'il y a des alignements des adresses, ce qui complique encore la chose...

    Du coup, je me demandais si je dois allouer un canari sur la stack, il va être placé automatiquement au début de la "stack frame" de ma fonction alors qu'en fait, je voudrais qu'il reste à la fin. Peux t-on empêcher le compilateur de déplacer une variable ? de ne pas faire d'alignement sur cette variable ?

    J'ai vu sur ton lien le code suivant : asm volatile("" :: "m" (canary));
    mais je t'avoue que je ne sais pas du tout ce que cela fait

    PS : J'ai vu aussi que GCC dans les dernières versions implémentait déjà ce principe avec -fstack-protector (au passage, fonctionne très mal sous Windows avec MinGW) mais je voudrais essayer de faire mon propre système de vérification et ainsi apprendre de nouvelles choses sur la stack

    Merci d'avance,
    Qui ne tente rien n'a rien !
    Ce qui ne nous tue pas nous rends plus fort !!
    Mon projet ZELDA en C++/Allegro
    http://www.tutoworld.com - Le Forum -
    Mes ressources Dotnet (cours, sources, tutos)
    --------------------------------------------
    + + =

    Ne pas oublier le Tag !

  11. #11
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 404
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 404
    Par défaut
    Au pire, pour chaque fonction tu fais une structure pour ses variables locales; dans la structure il y a des chances que les données restent dans l'ordre pour la plupart des plate-formes modernes.

    Note: Visual aussi implémente un canari dans le prologue et épilogue de ses fonctions.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  12. #12
    Membre chevronné
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Par défaut
    Comme dit Medinoc, tu peux faire quelque chose a base de structures:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    int func(char *arg) {
      struct locals {
        char buf[0x8];
        int canary;
      };
      struct locals vars;
      vars.canary = 0x12345678;
      strcpy(vars.buf, arg);
      if (vars.canary != 0x12345678) {
        printf("BoF\n");
        exit(1);
      }
      return 0x5;
    }
     
    int main(int main, char **argv) {
      func(argv[1]);
    }
    Qui donne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    dahtah@kali:~/test$ ./manual_canary $(python -c 'print "A"*12')
    BoF
    dahtah@kali:~/test$ echo $?
    1
    Apres tu as un probleme ici (securite parlant, je considere pas le cote crade de ce code):
    1. Ton canari est fixe. Il doit etre aleatoire, sinon un simple desassemblage te donne la valeur du canari


    Example:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    dahtah@kali:~/test$ objdump -d -j .text -M intel manual_canary | grep -i "func>:" -A 4
    0804847c <func>:
     804847c:	55                   	push   ebp
     804847d:	89 e5                	mov    ebp,esp
     804847f:	83 ec 28             	sub    esp,0x28
     8048482:	c7 45 f4 78 56 34 12 	mov    DWORD PTR [ebp-0xc],0x12345678
    dahtah@kali:~/test$ ./manual_canary $(python -c 'print "A"*8+"\x78\x56\x34\x12"+"B"*12+"\x44\x45\x46\x47"')
    Segmentation fault
    dahtah@kali:~/test$ dmesg | tail -n 1
    [454230.248431] manual_canary[4069]: segfault at 47464544 ip 47464544 sp bfca93d0 error 14
    Ici EIP est sous control de l'attaquant car le canari est previsible. C'est fini.

    En gros, tu peux le faire en C, mais c'est pas robuste du tout, car rien n'empeche ton compilo de reordonne la stack. Meme si ton canari est aleatoire, tu dois te prevenir d'infoleak (c'est a dire si l'attaquant peut lire l'espace memoire). stack-protector fait ca en stockant et en addressant le canari par rapport au TLS (Thread Local Storage). Etant donne que TLS est thread specific par definition et soumis a l'ASLR, c'est complique meme avec une infoleak de recuperer la valeur du canari:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     8048533:	8b 55 f4             	mov    edx,DWORD PTR [ebp-0xc]
     8048536:	65 33 15 14 00 00 00 	xor    edx,DWORD PTR gs:0x14
     804853d:	74 05                	je     8048544 <func+0x68>
     804853f:	e8 4c fe ff ff       	call   8048390 <__stack_chk_fail@plt>
     8048544:	c9                   	leave
    C'est pour ca que pour etre robuste, c'est fait juste avant la compilation. Apres si tu fais ca pour le fun, pourquoi pas .

  13. #13
    Membre Expert
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Par défaut
    En fait, je ne peux pas utiliser de structures dans mon cas, car je travaille sur un outil d'analyse de code source et donc le but est de modifier le moins possible les sources que je scanne. (en fait je récupère des codes sources en C que je passe dans mon logiciel d'analyse)

    Mon but pour simplifier serait juste de détecter une stack overflow (pour chaque fonction) due le plus souvent à un débordement de buffer, mais c'est sans doute trop compliqué sans toucher à l'assembleur (je ne sais pas coder en assembleur, j'ai juste des petites bases )

    Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    void foo(char* buf)
    {
         // L'idée serait d'injecter le canari ICI en se débrouillant 
        // pour ne pas qu'il soit déplacé par GCC
        char mon_canari_situe_en_fin_de_stack[0x08] = 0x12345678;
     
         // Le code de la fonction ********
         int dummy = 1234;
         strcpy(buf, "overflow !!!");
         printf("dummy = %d\n", dummy);
         // ***************************
     
        // Puis d'injecter la condition de vérification du canari ICI 
        // pour détecter un eventuel stack overflow
        if (mon_canari_situe_en_fin_de_stack != 0x12345678)
        {
            // stack overflow !!
            exit(-1);
        }
    }
     
    int main()
    {
        char buf[2];
        foo(buf);
    }
    Mais comment faire en langage C si possible ? (en ASM, je suis trop mauvais pour tenter d'injecter des lignes de code sans tout faire planter )

    A tout hasard, que fait cette instruction assembleur au final ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    char* buffer = alloca(10);
    	asm volatile("" :: "m" (buffer ));
    PS : Le canari peut être fixe dans mon cas car je ne traite pas la sécurité des codes scannés
    Qui ne tente rien n'a rien !
    Ce qui ne nous tue pas nous rends plus fort !!
    Mon projet ZELDA en C++/Allegro
    http://www.tutoworld.com - Le Forum -
    Mes ressources Dotnet (cours, sources, tutos)
    --------------------------------------------
    + + =

    Ne pas oublier le Tag !

  14. #14
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 404
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 404
    Par défaut
    Le bon terme, c'est stack smashing, pas stack overflow.

    Stack overflow, c'est quand c'est la pile elle-même qui déborde dans l'autre sens.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  15. #15
    Membre chevronné
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Par défaut
    Citation Envoyé par Aspic Voir le message
    A tout hasard, que fait cette instruction assembleur au final ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    char* buffer = alloca(10);
    	asm volatile("" :: "m" (buffer ));
    volatile specifie au compilateur qu'il ne peut optimiser l'acces a cette resource.
    la construction asm volatile est ce qui est important ici, c'est un "compiler fense". Ca empeche GCC d'optimiser le code entre les elements avant et apres cette barriere.

    Je pensais que ce code te permettrait de faire ce que tu veux, mais ca ne fonctionne pas (pour une raison que j'ignore):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    void stack_smashing(void) {
      volatile char canary[0x4] = {'A', 'B', 'C', 'D'};
      __asm__ __volatile__ ("" ::: "memory");
      int a = 0xffffffff;
      char buf[0x4] = {'Z', 'Z', 'Z', 'Z'};
      int d = 0xeeeeeeee;
    }
     
    int main(void) {
      stack_overflow();
      stack_smashing();
    }
    ASM genere:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    08048422 <stack_smashing>:
     8048422:	55                   	push   ebp
     8048423:	89 e5                	mov    ebp,esp
     8048425:	83 ec 10             	sub    esp,0x10
     8048428:	b0 41                	mov    al,0x41
     804842a:	ba 42 00 00 00       	mov    edx,0x42
     804842f:	88 d4                	mov    ah,dl
     8048431:	25 ff ff 00 ff       	and    eax,0xff00ffff
     8048436:	0d 00 00 43 00       	or     eax,0x430000
     804843b:	25 ff ff ff 00       	and    eax,0xffffff
     8048440:	0d 00 00 00 44       	or     eax,0x44000000
     8048445:	89 45 f4             	mov    DWORD PTR [ebp-0xc],eax
     8048448:	c7 45 fc ff ff ff ff 	mov    DWORD PTR [ebp-0x4],0xffffffff
     804844f:	c6 45 f0 5a          	mov    BYTE PTR [ebp-0x10],0x5a
     8048453:	c6 45 f1 5a          	mov    BYTE PTR [ebp-0xf],0x5a
     8048457:	c6 45 f2 5a          	mov    BYTE PTR [ebp-0xe],0x5a
     804845b:	c6 45 f3 5a          	mov    BYTE PTR [ebp-0xd],0x5a
     804845f:	c7 45 f8 ee ee ee ee 	mov    DWORD PTR [ebp-0x8],0xeeeeeeee
     8048466:	c9                   	leave  
     8048467:	c3                   	ret
    On voit bien que la stack sera comme ca, ce qui ne protege pas:
    [ebp-0x4] a
    [ebp-0x8] d
    [ebp-0xc] canary
    [ebp-0x10] buf
    J'ai jamais utilise un "compiler fense", donc c'est possible que je m'en server mal.

  16. #16
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 815
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 815
    Par défaut
    Et le vieux truc

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #include <iostream>
     
    using namespace std;
     
     
    int  main ()
    {
    	int tab1[1024] = {0};
    	double tab2[2048] = {0.0};
    	char tab3[58] = {'\0'};
     
    	cout << "Size tab1: " << sizeof(tab1)/ sizeof(tab1[0]) << endl;
    	cout << "Size tab2: " << sizeof(tab2)/ sizeof(tab2[0]) << endl;
    	cout << "Size tab3: " << sizeof(tab3)/ sizeof(tab3[0]) << endl;
     
    	return 0;
    }

  17. #17
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 500
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 500
    Billets dans le blog
    1
    Par défaut
    Cette solution ne marche que dans le même scope que la déclaration / définition du tableau. Dés que tu rentres dans le scope imbriqué de la fonction, tu n'as plus connaissance du tableau mais uniquement du pointeur sur le premier élément. Cette technique ne fonctionne donc pas (voir le commentaire dans la fonction foo() du message #1).

Discussions similaires

  1. Réponses: 5
    Dernier message: 12/12/2013, 12h43
  2. Passer l'adresse d'un tableau statique
    Par Fooshi dans le forum C
    Réponses: 13
    Dernier message: 13/08/2010, 18h25
  3. Réponses: 5
    Dernier message: 02/05/2009, 16h27
  4. taille tableau statique
    Par Rniamo dans le forum C++
    Réponses: 14
    Dernier message: 14/06/2008, 17h16
  5. qbasic : taille d'un tableau
    Par clood200 dans le forum Basic
    Réponses: 2
    Dernier message: 16/09/2003, 08h26

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo