Próbuję przejąć kontrolę nad przepełnieniem stosu. Po pierwsze, tutaj jest przykład kodu C skompilowany na x32 VM Linux (gcc -fno-stack-protector -ggdb -o first first.c
)Przepełnienie bufora pojawiło się, zanim się spodziewano.
#include "stdio.h"
int CanNeverExecute()
{
printf("I can never execute\n");
return(0);
}
void GetInput()
{
char buffer[8];
gets(buffer);
puts(buffer);
}
int main()
{
GetInput();
return(0);
}
Następnie debugger (smak intel): zrzut kodu asemblera dla funkcji GetInput
:
0x08048455 <+0>: push ebp
0x08048456 <+1>: mov ebp,esp
0x08048458 <+3>: sub esp,0x28
0x0804845b <+6>: lea eax,[ebp-0x10]
Tutaj możemy zauważyć, że sub esp, 0x28 rezerwuje 40 bajtów dla zmiennej buforowej (prawy?). Funkcja CanNeverExecute
znajduje się pod adresem 0x0804843c
. Tak więc, aby uruchomić funkcję CanNeverExecute
, muszę umieścić 40 bajtów w zmiennej buforowej, a następnie 8 bajtów dla zapisanego wskaźnika bazowego, a następnie 8 bajtów wskaźnika powrotu, który chcę zmienić.
Potrzebuję więc ciągu 48 znaków ASCII plus \x3c\x84\x04\x08
na końcu (adres funkcji CanNeverExecute
). Tak jest w teorii. Ale w praktyce potrzebuję tylko 20 bajtów przed adresem wskaźnika powrotu:
~/hacktest $ printf "123456789\x3c\x84\x04\x08" | ./first
123456789..
I can never execute
Illegal instruction (core dumped)
Dlaczego potrzebuje tylko 20 bajtów zamiast 48? Gdzie jest mój błąd?