Странный путь выполнения, вызванный переполнением буфера стека - PullRequest
2 голосов
/ 02 марта 2012

Я прочитал несколько статей о переполнении буфера стека, например, this , и узнал, как злоумышленники могут использовать ошибку переполнения буфера стека, перезаписывая указатели функций.Затем я написал небольшую программу для демонстрации атаки:

#include <stdio.h>
#include <string.h>

void fun1 ( char * input ) {
    char buffer[10];
    strcpy( buffer, input );
    printf( "In fun1, buffer= %s\n", buffer );
}

void fun2 ( void ) {
    printf ( "HELLO fun2!\n" );
}

int main ( int argc, char * argv[] )
{
    printf ( "Address of fun2: %p\n", fun2 );
    fun1( "abcdefghijklmnopqrstuv\x52\x84\x04\x08" );
    return 0;
}

Программа была скомпилирована с GCC 4.5.1 под Fedora 14 x86.Ниже приводится вывод:

$ ./exp01

Адрес fun2: 0x8048452

В fun1, buffer = abcdefghijklmnopqrstuvR�

ПРИВЕТ fun2!

ПРИВЕТ fun2!

Мы видим, что fun2 () был вызван успешно, но я не знаю, почему он запускался дважды.Затем я GDBed это (см. Ниже).(Я знаю только некоторые базовые инструкции о GDB ╮ ( ̄ ▽  ̄) ╭)

Я погуглил некоторые ключевые слова, такие как «__libc_csu_fini ()», но не нашел четкого способа, который мог бы помочь мне понятьпуть выполнения программы.Я слишком мало знаю о компиляторе и внутренней структуре процесса, поэтому считаю, что мне, возможно, придется найти некоторые книги или статьи, которые подробно описывают эти вещи.Любое предложение?Спасибо!


Запись GDB:

(gdb) список

7 printf ("В fun1, буфер =%s \ n ", буфер);

8}

9

10 void fun2 (void) {

11 printf (" ПРИВЕТ fun2! \ "n ");

12}

13

14 int main (int argc, char * argv [])

15 {

16 printf ("Адрес fun2:% p \ n", fun2);

(gdb)

17 fun1 ("abcdefghijklmnopqrstuv \ x52 \ x84 \ x04 \ x08");

18 return 0;

19}

(gdb) перерыв 16

Точка останова 1 в 0x804846f: файл hello.c, строка 16.

(gdb) run

Запуск программы: / home / yuliang / test / hello

Точка останова 1, главная (argc = 1, argv = 0xbffff394) в hello.c: 16

16 printf ("Адрес fun2:% p \ n", fun2);

Отсутствует отдельный debuginfos, используйте: debuginfo-install glibc-2.13-2.i686

(gdb) step

Адрес fun2: 0x8048452

17 fun1 ("abcdefghijklmnopqrstuv \ x52 \ x84 \ x04 \ x08 ");

(gdb)

fun1 (input = 0x804859a" abcdefghijklmnopqrstuvR \ 204 \ 004 \ b ") в hello.c: 6

6 strcpy (буфер, ввод);

(gdb)

7 printf ("In fun1, buffer =% s \ n", buffer);

(gdb)

В fun1, buffer = abcdefghijklmnopqrstuvR�

8}

(gdb)

fun2 () в hello.c: 10

10 void fun2 (void) {

(gdb)

11 printf ("ПРИВЕТ fun2! \ N");

(gdb)

ПРИВЕТ fun2!

12}

(gdb)

0x08048500 в __libc_csu_fini ()

(gdb)

Один шаг до выхода из функции __libc_csu_fini,

, в которой нет информации о номере строки.

fun2 () в hello.c: 10

10 void fun2 (void) {

(gdb)

11 printf ("ПРИВЕТ fun2! \ N");

(gdb)

ПРИВЕТ fun2!

12}

(gdb)

Нет доступапамять по адресу 0x76757477

(gdb)

Один шаг до выхода из функции __libc_csu_init,

без информации о номере строки.

0x009aae36 в __libc_start_main () из /lib/libc.so.6

(gdb)

Один шаг до выхода из функции __libc_start_main,

, которая не имеет информации о номере строки.

Программа завершена с кодом 0241.

(gdb)

1 Ответ

0 голосов
/ 29 марта 2012

При запуске вашей программы в gdb прервитесь незадолго до strcpy() и посмотрите на кадр стека (именно там хранится eip сохранения).затем запустить до вскоре после printf() и снова взглянуть на сохраненный eip (команда info frame).

, так как вы передаете адрес функции fun2() в fun1(), он перезапишет сохраненный eip, и как только вызывается return (неявно в вашем случае), будет выполнена следующая инструкция (которая даетсяeip, а в вашем случае это адрес fun2())

И не забудьте прочитать Разбить стек ради удовольствия и прибыли от aleph1

...