2011-12-06 6 views
2

Le code ci-dessous provient de l'article bien connu Smashing The Stack For Fun And Profit.Mon code de débordement ne fonctionne pas

void function(int a, int b, int c) { 
    char buffer1[5]; 
    char buffer2[10]; 
    int *ret; 
    ret = buffer1 + 12; 
    (*ret)+=8; 
} 

void main() { 
    int x; 
    x=0; 
    function(1,2,3); 
    x=1; 
    printf("%d\n",x); 
} 

Je pense que je dois expliquer ma cible de ce code. Le modèle de pile est ci-dessous. Le nombre en dessous du mot est le nombre d'octets de la variable dans la pile. Donc, si je veux réécrire RET pour passer l'instruction que je veux, je calcule le décalage de buffer1 à RET est 8 + 4 = 12. Depuis l'architecture est Linux x86.

buffer2 buffer1 BSP RET a b c 
(12) (8)  (4) (4) (4) (4) (4) 

Je veux ignorer la déclaration x=1; et laisser printf() sortie 0 à l'écran.

Je compilez le code avec:

gcc stack2.c -g 

et l'exécuter dans gdb:

gdb ./a.out 

gdb me donne le résultat comme ceci:

Program received signal SIGSEGV, Segmentation fault. 
main() at stack2.c:17 
17 x = 1; 

Je pense que Linux utilise certains mécanisme de protection contre le débordement de la pile. Peut-être que Linux stocke l'adresse RET à un autre endroit et compare l'adresse RET dans la pile avant le retour des fonctions.

Et quel est le détail du mécanisme? Comment est-ce que je devrais réécrire le code pour rendre la sortie de programme 0? OK, le code de démontage est ci-dessous.Il vient de la sortie de gdb car je pense qu'il est plus facile à lire pour vous.Et quelqu'un peut me dire comment coller une séquence de code long? Copiez et collez un par un fait moi aussi fatigué ...

Dump of assembler code for function main: 
0x08048402 <+0>: push %ebp 
0x08048403 <+1>: mov %esp,%ebp 
0x08048405 <+3>: sub $0x10,%esp 
0x08048408 <+6>: movl $0x0,-0x4(%ebp) 
0x0804840f <+13>: movl $0x3,0x8(%esp) 
0x08048417 <+21>: movl $0x2,0x4(%esp) 
0x0804841f <+29>: movl $0x1,(%esp) 
0x08048426 <+36>: call 0x80483e4 <function> 
0x0804842b <+41>: movl $0x1,-0x4(%ebp) 
0x08048432 <+48>: mov $0x8048520,%eax 
0x08048437 <+53>: mov -0x4(%ebp),%edx 
0x0804843a <+56>: mov %edx,0x4(%esp) 
0x0804843e <+60>: mov %eax,(%esp) 
0x08048441 <+63>: call 0x804831c <[email protected]> 
0x08048446 <+68>: mov $0x0,%eax 
0x0804844b <+73>: leave 
0x0804844c <+74>: ret 


Dump of assembler code for function function: 
0x080483e4 <+0>: push %ebp 
0x080483e5 <+1>: mov %esp,%ebp 
0x080483e7 <+3>: sub $0x14,%esp 
0x080483ea <+6>: lea -0x9(%ebp),%eax 
0x080483ed <+9>: add $0x3,%eax 
0x080483f0 <+12>: mov %eax,-0x4(%ebp) 
0x080483f3 <+15>: mov -0x4(%ebp),%eax 
0x080483f6 <+18>: mov (%eax),%eax 
0x080483f8 <+20>: lea 0x8(%eax),%edx 
0x080483fb <+23>: mov -0x4(%ebp),%eax 
0x080483fe <+26>: mov %edx,(%eax) 
0x08048400 <+28>: leave 
0x08048401 <+29>: ret 

-je vérifier le code et trouver assembler une erreur au sujet de mon programme, et je dois réécrire (*ret)+=8-(*ret)+=7, depuis 0x08048432 <+48> moins 0x0804842b <+41> est 7.

+1

Vérifiez l'assemblage généré, probablement votre fonction a été insérée. – kan

+0

Je vous promets que la fonction n'a pas été intégrée, puisque j'ai vérifié le code d'assemblage. –

+1

Vous supposez que 'x = 1' génère 8 octets de code d'assemblage et que la pile est disposée comme vous l'avez montré (il pourrait aussi y avoir d'autres choses). Ajouter la liste d'assemblage et la réponse deviendra vraiment évidente. – Skizz

Répondre

2

Parce que cet article date de 1996 et que les hypothèses sont incorrectes.

Se reporter à "Smashing Stack moderne pour le plaisir et le profit"

http://www.ethicalhacker.net/content/view/122/24/

À partir du lien ci-dessus:

Cependant, le compilateur GNU C (gcc) a évolué depuis 1998, et par conséquent, beaucoup de gens se demandent pourquoi ils ne peuvent pas obtenir les exemples pour travailler pour eux, ou s'ils obtiennent le code pour travailler, pourquoi ils ont dû faire les changements qu'ils ont faits.

+0

Merci beaucoup! –

0

la fonction function certains écrase place de la pile en dehors de son o wn, qui est ce cas est la pile de main. Ce qu'il écrase, je ne sais pas, mais il provoque la faute de segmentation que vous voyez. Il peut s'agir d'une protection utilisée par le système d'exploitation, mais il se pourrait aussi que le code généré fasse juste quelque chose de mal quand une mauvaise valeur est à cette position sur la pile.

Ceci est un très bon exemple de ce qui peut arriver lorsque vous écrivez en dehors de votre mémoire allouée. Il pourrait tomber en panne directement, il pourrait se planter quelque part complètement différent, ou si ne pourrait pas planter du tout, mais au lieu de faire un mauvais calcul.

+0

-1 Rien n'empêche d'écraser le cadre de la pile d'une autre fonction jusqu'à la racine de la pile. Dans ce cas, il écrit probablement au-delà du début de la pile (en fonction du code qui appelle 'main()') –

+2

Une erreur de segmentation est provoquée par un processus écrit en dehors de sa mémoire. Puisque les deux fonctions appartiennent au même processus, elles peuvent gribouiller sur la mémoire de l'autre sans élever SIGSEGV (à moins que le compilateur ou l'OS n'ait fait quelque chose de * très * étrange pour protéger contre la destruction de la pile). – Jonathan

0

Essayez ret = buffer1 + 3;

Explication: ret est un pointeur de nombre entier; l'incrémenter de 1 ajoute 4 octets à l'adresse sur les machines 32 bits.

+0

Cela ne fonctionne pas. –

+3

Imprime l'adresse de 'x',' a' et 'buffer1'. Cela devrait vous donner une idée du côté de l'erreur. PS: "ne fonctionne pas" n'est jamais utile comme message d'erreur. Merci de ne plus jamais utiliser cette phrase. :-) –

+0

OK.J'ai fatigué de réécrire "ret = buffer1 + 3" et exécuter le programme.Et je poste le premier commentaire après avoir fatigué le code.Mais ça ne fonctionne pas. –