2012-11-11 12 views
5

Próbowałem pominąć instrukcję, zmieniając adres zwrotny poprzez rozbijanie stosu. Poniższy kod pomija ++ w głównej i wypisuje wynik "1 3". Wykonałem ten kod na 32-bitowej maszynie intel.Pomijanie instrukcji przy użyciu rozbijania stosów

#include<stdio.h> 
void fun(int a,int b) { 
    // buffer 
    char buf[8]; 
    char *p; 
    p = (char *)buf+24; 
    *p=*p+5; 
    return; 
} 

int main() { 
    int a=1,b=2; 
    fun(a,b); 
    a++; 
    b++; 
    printf("%d %d",a,b); 
} 

Nie jestem w stanie zrozumieć, dlaczego adres powrotu jest przechowywany z przesunięciem 24 bajtów od adresu początkowego buf. Próbowałem wykonać ten sam kod na innym 32-bitowym komputerze intel i musiałem użyć przesunięcia 20 bajtów zamiast 24 bajtów. Moje zrozumienie przedstawiłem na poniższej ilustracji. Nie jestem pewien, co wypełnia lukę reprezentowaną przez "?" Na rysunku. Czy gcc umieścił tam jakąś wartość kanarową, czy też czegoś mi brakuje?

Link do rysunku: http://www.cse.iitb.ac.in/~shashankr/stack.png

Smashing the stack example3.c confusion samo pytanie, ale nie mógł wyjaśnić przyczynę przemieszczenia w ogóle.

Poniższy rysunek przedstawia widok stosu uzyskanego poprzez umieszczenie punktu przerwania w funkcji.

stack content http://www.cse.iitb.ac.in/~shashankr/stack4.png

Poniżej znajduje się kod montaż do głównego i zabawy:

Dump of assembler (fun): 
0x08048434 <+0>: push %ebp 
0x08048435 <+1>: mov %esp,%ebp 
0x08048437 <+3>: sub $0x18,%esp 
0x0804843a <+6>: mov %gs:0x14,%eax 
0x08048440 <+12>: mov %eax,-0xc(%ebp) 
0x08048443 <+15>: xor %eax,%eax 
0x08048445 <+17>: lea -0x14(%ebp),%eax 
0x08048448 <+20>: add $0x18,%eax 
0x0804844b <+23>: mov %eax,-0x18(%ebp) 
0x0804844e <+26>: mov -0x18(%ebp),%eax 
0x08048451 <+29>: movzbl (%eax),%eax 
0x08048454 <+32>: add $0x5,%eax 
0x08048457 <+35>: mov %eax,%edx 
0x08048459 <+37>: mov -0x18(%ebp),%eax 
0x0804845c <+40>: mov %dl,(%eax) 
0x0804845e <+42>: mov -0xc(%ebp),%eax 
0x08048461 <+45>: xor %gs:0x14,%eax 
0x08048468 <+52>: je  0x804846f <fun+59> 
0x0804846a <+54>: call 0x8048350 <[email protected]> 
0x0804846f <+59>: leave 
0x08048470 <+60>: ret  


Dump of assembler (main) 
0x08048471 <+0>: push %ebp 
0x08048472 <+1>: mov %esp,%ebp 
0x08048474 <+3>: and $0xfffffff0,%esp 
0x08048477 <+6>: sub $0x20,%esp 
0x0804847a <+9>: movl $0x1,0x18(%esp) 
0x08048482 <+17>: movl $0x2,0x1c(%esp) 
0x0804848a <+25>: mov 0x1c(%esp),%eax 
0x0804848e <+29>: mov %eax,0x4(%esp) 
0x08048492 <+33>: mov 0x18(%esp),%eax 
0x08048496 <+37>: mov %eax,(%esp) 
0x08048499 <+40>: call 0x8048434 <fun> 
0x0804849e <+45>: addl $0x1,0x18(%esp) 
0x080484a3 <+50>: addl $0x1,0x1c(%esp) 
0x080484a8 <+55>: mov $0x80485a0,%eax 
0x080484ad <+60>: mov 0x1c(%esp),%edx 
0x080484b1 <+64>: mov %edx,0x8(%esp) 
0x080484b5 <+68>: mov 0x18(%esp),%edx 
0x080484b9 <+72>: mov %edx,0x4(%esp) 
0x080484bd <+76>: mov %eax,(%esp) 
0x080484c0 <+79>: call 0x8048340 <[email protected]> 
0x080484c5 <+84>: leave 
0x080484c6 <+85>: ret  
+0

Proszę zauważyć, że ustaliłem wartość 24 metodą prób i błędów. Ponadto, wartość 5 do gdb demontażu głównej funkcji. – shashank

+0

Zmienna 'p' powinna również znajdować się na stosie, więc mogę dodać 4 bajty, jak sądzę. Nie jestem pewien, skąd pochodzi reszta. –

+0

Z perspektywy czasu jest również prawdopodobne, że argumenty "a" i "b" nigdy nie są usuwane ze stosu ze względu na wydajność, w związku z czym stanowią pozostałą część pamięci. –

Odpowiedz

2

Uważam, że odpowiedź jest niczym. Czy masz różne wersje gcc? W każdym razie kompilator może przydzielić nieco więcej stosu niż to konieczne. Być może jest to początkowe "zgadywanie" oparte na liczbie zmiennych, ale nie jest ono zmniejszane przez etapy optymalizacji, które mogą przenosić dowolną zmienną do rejestru. Lub jest to jakiś zbiornik do zapisywania rejestrów ekx, ebp lub innych, na wypadek gdyby podprogram był potrzebny.

Istnieje jedna zmienna adresu stałego w celu rozwiązania problemu: a. Adres zwrotny = & a [-1].

+0

Tak, maszyny mają różne wersje gcc. Być może masz rację, jeśli gcc przyznaje dodatkowe miejsce na stosie. Kiedy wykonałem ten sam kod na drugiej maszynie, zauważyłem, że zmniejszył się rozmiar ramki stosu. Może to być również spowodowane tym, że gcc na pierwszej maszynie użył wartości kanarka. Kiedy zrobiłem strcpy, aby przepełnić bufor, dostałem komunikat o rozbiciu stosu na pierwszej maszynie.Tak się nie stało na drugim komputerze, ponieważ gcc jest starszej wersji i być może nie użył wartości kanarka. Ponadto, dziękuję za sugestię obejścia, aby znaleźć lokalizację adresu zwrotnego za pośrednictwem adresu. – shashank

Powiązane problemy