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
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
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. –
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. –