2010-06-18 44 views
-3

Bonjour à tous! J'essaie de comprendre comment fonctionne le débordement de tampon. En ce moment, je suis en train de déterminer l'adresse de retour d'une fonction que je suis supposé changer pour effectuer une attaque de débordement de tampon. J'ai écrit un programme simple basé sur un exemple que j'ai lu sur internet. Ce que fait ce programme est qu'il crée un pointeur entier pour stocker l'adresse de retour de la fonction dans la pile. Pour ce faire, (étant donné que je comprends comment les variables d'une fonction/programme sont organisées dans la pile), j'ajoute 8 à l'adresse de la variable tampon et la place comme valeur de ret. Je ne fais rien ici qui changerait l'adresse contenue dans l'emplacement de l'adresse de retour de func. MISE À JOUR: J'ai modifié le programme un peu, donc il imprime l'adresse de la pile du paramètre func a. Comme vous pouvez le voir, la distance entre a et buffer est d'environ 8 octets, ce qui signifierait probablement, en fonction de la disposition de la pile, que FP et EIP (adresse de retour func) sauvegardés sont entre les deux. Ai-je raison?l'adresse de retour de la fonction est différente de sa valeur supposée, buffer overflow, AIDE SVP

Voici le programme:

void func(int a){ 
    char buffer[3]; 

    int *ret; 

    ret = buffer + 11; // this is the configuratio which made the whole program works... This now points to the address containing func's return address 

    printf (" address of a is %d\n", &a); 

    printf ("address of buffer is %x\n", buffer); 

    printf ("address of ret is %x\n", ret); 

    printf ("value of ret is %x\n", (*ret)); 

} 

void main(){ 
    int num; 

    num = 0; 

    func(num); 

    num = 1; 

    printf("Num now is %d", num); 
} 

sortie du programme quand se fait étét exécutée:

alt text http://img20.imageshack.us/img20/2034/72783404.png

Comme vous pouvez le voir, j'imprime l'adresse des variables tampon et ret. J'ai ajouté une instruction supplémentaire imprimant la valeur de la variable ret (supposée emplacement de l'adresse de retour de func, donc ceci devrait imprimer l'adresse de l'instruction suivante qui sera exécutée après que fonc retourne de l'exécution).

Voici le vidage qui montre l'adresse supposée de l'instruction à exécuter après le retour de func. (Souligné en vert) Comme vous pouvez le voir, cette valeur est très différente de la valeur imprimée contenue dans la variable ret.

alt text http://img717.imageshack.us/img717/8273/assemblycodecopy.png

Ma question est, pourquoi sont-ils différents? (bien sûr dans l'hypothèse que ce que j'ai fait est correct). Sinon, qu'ai-je fait de mal? Ma compréhension de la pile d'exécution du programme est-elle fausse? S'il te plaît, aide-moi à comprendre ça. Mon projet est attendu la semaine prochaine et je l'ai à peine touché. Je suis désolé si je suis exigeant, j'ai terriblement besoin de votre aide.

+8

Veuillez inclure le texte de votre code actuel (pas seulement des captures d'écran) dans votre message. –

+0

Je suis désolé, mais il y a tout ce qu'il y a. – ultrajohn

+0

Je suis désolé s'il vous plaît attendre – ultrajohn

Répondre

1

Pour le programme suivant

int main(int argc, char **argv) { 
    int v[2]; 

    return 0; 
} 

La mise en page de la pile est essentiellement les éléments suivants:

 
     ------------- 
      arg n 
     ------------- 
     ......... 
     ------------- 
0x1010  arg 0 
     ------------- 
0x100C ret address 
     ============= 
0x1008  old fp 
     ------------- 
0x1004  v[1] 
     ------------- 
0x1000  v[0] 
     ------------- 

Vous pouvez trouver l'adresse de retour principale en utilisant v + 3.

En supposant que la adresses placées sur le côté gauche de la pile, v a l'adresse 0x1000, l'adresse de retour a l'adresse (v + 3 => 0x1000 + 4 * 3 = 0x10 0C)

+0

est-ce que dans l'hypothèse que cela, v prend 2 octets, ancien fp prend 1 octet? – ultrajohn

+0

v prend 4 octets, l'ancien fd prend 4 octets. –

+0

mais pourquoi n'en ajoutez-vous que 3? ?? suis confus, ne devriez-vous pas ajouter 8 à la place? – ultrajohn

1

Tout d'abord, notez que l'adresse du tampon est un nombre impair 0xbffffd51 et que vous ajoutez 8 pour obtenir 0xbffffd59. Je serais très surpris si l'adresse de retour sur la pile n'était pas alignée sur une adresse à quatre octets. Selon le compilateur, la structure de la pile peut varier selon le compilateur (par exemple, même si buffer est le premier dans le code source, le compilateur peut mettre ret plus haut dans la pile), vous devrez donc expérimenter avec vos valeurs. Je voudrais faire un couple de choses:

  1. Changer le tampon pour être 4 octets.
  2. Expérimentez avec différents décalages. J'ai le sentiment que vous devrez peut-être chercher 12 octets ou même 16 octets pour trouver votre adresse de retour.
+0

ouais, d'après ce que j'ai compris, la disposition de la pile devrait ressembler à ceci quand func est appelée, de l'adresse mem supérieure à l'adresse mem inférieure, | nums value | ret | sfp (ebp) | tampon | , donc la distance entre le tampon et ret dans la pile, devrait être comme 8, – ultrajohn

+0

@ultrajohn - et pourtant ce n'est pas 8 donc votre compréhension est incorrecte. Avez-vous essayé les changements que j'ai recommandés? –

+0

ouais, j'ai essayé d'utiliser différents décalages, et je n'ai pas pu obtenir la valeur correcte de l'adresse, dans un cas, la valeur récupérée est correcte pour ses 7 premiers chiffres de gauche, sauf le dernier exemple: Si la valeur correcte est 0808425d, j'ai rencontré une valeur dans un décalage particulier qui ressemble à ceci, 808425d1, et je ne sais pas pourquoi? – ultrajohn

0

Bien sûr, vous ne pouvez pas modifier le num d'origine sauf si vous lui passez le pointeur; donc dans l'ensemble, num first est 0, alors il est 1, et il n'est jamais vraiment modifié par la func. L'adresse de a (&a) dans func est l'adresse de la copie locale (en valeur) de l'argument, probablement une adresse sur la pile dans la plupart des cas. Et qu'est-ce que ret pointerait? Vous avez un tampon de 3 caractères, et vous obtenez l'adresse au-delà; vous devez le considérer maintenant comme un pointeur vers les ordures, même si vous pointez probablement vers quelque chose d'intéressant, selon la façon dont les variables locales sont "organisées" en mémoire. Vous ne pouvez donc pas être sûr à 100% qu'il pointe bien l'adresse de retour. Vous supposez ce qui suit:

 
0 4 bytes (for char, assuming 4bytes alignment) 
4 4 bytes (for whatever, maybe argument) 
8 4 bytes (return address) 

Et cela dépend. Cela dépend de l'architecture. cela dépend de la façon dont le compilateur "traduit" le code de la fonction. Laissez-nous imaginer x86. Ce qui suit est un moyen raisonnable de faire fonction

 
func: 
    push ebp ; save some regs... 
    push eax ; or with pusha? 
    mov ebp, esp 
    push 0 ; for char a[3] 
    mov eax, ebp 
    add eax, 4 ; -4 + 8 
    push eax ; for int *ret 
    ; -4(ebp) gives a 
    ; -8(ebp) gives int *ret 
    ; so ebp-4 is the pointer to a, we 
    ; add 8, to obtain ebp+4, which points 
    ; to saved ebp... missing the ret ptr 
    ; (other code...) 
    mov esp, ebp 
    pop eax ; or with popa? 
    pop ebp 
    ret 

et si les reg sauvegardés sont plus? que se passe-t-il si l'ordre de char a [4] et int * ret est inversé? Comment pouvez-vous savoir? Vous ne pouvez rien supposer, à moins que vous n'écriviez vous-même le code directement dans asm, dans ce cas vous pouvez contrôler exactement ce qui se passe. Sinon, un code C fonctionnel pour faire ce que vous voulez fonctionnerait par hasard ...

+0

J'ai écrit un [n], ou char * a ... au lieu de char buffer ... mélangé un peu avec un (int arg)/tampon, et int * ret, fondamentalement oublié l'argument ... peu importe: le même raisonnement fonctionne toujours: c'est-à-dire que vous ne pouvez pas supposer que la disposition des choses sur la pile sera exactement celle de différents compilateurs (et bien sûr, sur différents processeurs, mais cette affaire n'est probablement pas de votre intérêt); Même si l'utilisation d'un pointeur de trame est une bonne idée sur x86, personne ne vous assure qu'il est utilisé, et pas de la même manière, par tous les compilateurs. – ShinTakezou

+0

je l'ai résolu, tnx de toute façon .. – ultrajohn