После завершения работы над фрагментом управляющего кода следует решить вопрос о передачи ему управления из программы переполнения буфера. Для этого нужно подменить сохраненное в стеке значение регистра EIP на адрес управляющего кода. Когда функция bof
уязвимой программы попытается вернуться в функцию main по команде ret, она восстановит из стека сохраненное там значение регистра EIP и по команде перехода jmp перейдет по восстановленному адресу. Но где в памяти будет расположен управляющий код? Конкретнее, на какой адрес нужно подменить содержимое регистра EIP, сохраненное в стеке? При помощи функции fread
данные из файла считываются в размещенный в стеке восьмибайтовый буфер buffer. Известно, что программный код полезной нагрузки в конечном счете будет загружен из файла в стек. В UNIX-подобных системах во всех программах стек начинается с одного и того же адреса. Поэтому последнее, что осталось сделать, – это написать программу определения смещения области размещения программного кода полезной нагрузки в стеке относительно его начала.Перед завершением своей работы функция передает вызвавшей ее программе код возврата в регистре EAX, чтобы та знала об успешном или неуспешном выполнении функции. Чтобы узнать ассемблерную реализацию фрагмента программы, отвечающего за передачу кода завершения, оттранслируем и дизассемблируем следующую программу:$ cat ret.c
int main
{
return(0);
}
$ gcc ret.c -o ret
$ gdb ./ret
(gdb) disas main
Dump of assembler code for function main:
0x8048430 : push %EBP
0x8048431 : mov %ESP,%EBP
0x8048433 : mov $0x0,%EAX <– here it is :)
0x8048438 : pop %EBP
0x8048439 : ret
0x804843a : mov %ESI,%ESI
0x804843c : nop
0x804843d : nop
0x804843e : nop
0x804843f : nop
End of assembler dump.
(gdb)Далее, вместо выполнения оператора возврата return
(значение) пропустим его и перепишем значение ESP в регистр EAX. Таким способом значение регистра ESP может быть назначено переменной. Вот пример программы, отображающей содержимое регистра ESP:–get_ESP.c–
unsigned long get_ESP(void)
{
__asm__(“movl %ESP,%EAX”);
}
int main
{
printf(“ESP: 0x%x\n”, get_ESP);
return(0);
}
–get_ESP.c–