Вопрос с защитой стека и переполнением буфера - PullRequest
3 голосов
/ 19 июля 2011

Я занимаюсь исследованием переполнения буфера, и мне было интересно, как работает защита от перебора стека

У меня есть этот код:

int main( )
{ 
    char Buf[16];
    printf(“Digite o seu nome: ”);
    gets(Buf);
    printf(“%s”,Buf);
return 0;
} 

Я компилирую его с помощью gcc

и затем я вставил несколько символов, чтобы заполнить буфер

Сначала я поставил 16 символов

$ ./Exemplo1

Digite o seuome: AAAAAAAAAAAAAAAA

Ола АААААААААААААААА

Это нормально, потому что буфер имеет правильный размер

Далее я попробую 24 символа

$ ./Exemplo1

Digite o seu nome: AAAAAAAAAAAAAAAAAAAAAAAA

Ола АААААААААААААААААААААААА

Почему это все еще работает?

не должно ли это привести к завершению программы !?

Программа прекращает работу, только когда я ставлю 25 или более символов

. / Exemplo1

Digite o seu nome: AAAAAAAAAAAAAAAAAAAAAAAAA

Ола ААААААААААААААААААААААААА

* обнаружено разрушение стека *: ./Exemplo1 прекращено

Почему? что после буфера, который не является адресом возврата? То, о чем я читал и что я понимаю, это то, что оно должно иметь канареечное значение, но оно должно завершить программу, если это значение изменилось, и с 24 символами, записанными в буфер, не должно ли это все же дать мне обнаружение разрушения стека если адрес возврата не изменился, но канарское значение изменилось.

Спасибо.

Ответы [ 4 ]

6 голосов
/ 19 июля 2011

Из моего краткого прочтения сгенерированной сборки я думаю, что вот что происходит (gcc 4.4.5 на 64-битной Ubuntu).

Канарское слово - двойное слово (8 байт).Стек - включая канарейку - увеличивается с шагом 16 байтов.Канарейка находится прямо в конце стека кадра.Чтобы одновременно удовлетворить все три требования, gcc может потребоваться вставить заполнение между вашими автоматическими переменными и канарейкой.

Поскольку в вашем коде Buf имеет длину 16 байтов, gcc размещает 8 байтовзаполнения между Buf и канарейкой (необходим для того, чтобы размер стекового кадра был кратным 16 байтам).Это объясняет, почему вы можете ввести до 24 символов, не вызывая определение разрушения стека.

Если я изменю Buf на длину 8 байт, больше нет необходимости в заполнении, и ввод 9 символов запускает защиту:

#include <stdio.h>

int main( )
{ 
    char Buf[8];
    printf("Digite o seu nome: ");
    gets(Buf);
    printf("%s",Buf);
    return 0;
 }

aix@aix:~$ ./a.out 
Digite o seu nome: AAAAAAAA
AAAAAAAA

aix@aix:~$ ./a.out 
Digite o seu nome: AAAAAAAAA
*** stack smashing detected ***: ./a.out terminated

Очевидно, это зависит от компилятора, аппаратной платформы, флагов компилятора и т. Д.

Само собой разумеется, что не следует ожидать, что этот механизм будет пуленепробиваемым.

Если вы хотите поэкспериментировать дальше, попробуйте скомпилировать код с разными размерами буфера и с / без -fno-stack-protector.Если вы используете -S для генерации кода сборки, вы сможете увидеть, как сгенерированный код изменяется при настройке параметров.

0 голосов
/ 19 июля 2011

В настоящее время большинство компиляторов включают файлы cookie стека или другую форму защиты стека.Вероятно, это ProPolice на работе http://en.wikipedia.org/wiki/Buffer_overflow_protection#GCC_Stack-Smashing_Protector_.28ProPolice.29

0 голосов
/ 19 июля 2011

Фактический размер буфера может быть больше, чем указанный вами размер, или в стеке рядом с буфером находится больше. Пройдя границу буфера, вы либо записываете в дополнительную память в буфере, либо перезаписываете другое содержимое стека. Это нехорошо, так как он может уничтожить некоторые ваши локальные переменные, но пока не перезапишет адрес возврата.

Только если вы пишете за пределами выделенного кадра локального стека и перезаписываете адрес возврата функции, которая выполняется в данный момент, могут произойти плохие вещи. Если вам повезет, ваша программа просто вылетает. Но что именно произойдет, предугадать сложно.

0 голосов
/ 19 июля 2011

Компилятор не дает никаких гарантий относительно организации данных в стеке. Буфер buf[] может быть размещен рядом с критическими данными, такими как канарейка, указатель старого стека и адрес возврата; или между ними может быть дополнительное пространство. В этом случае, похоже, что там, вероятно, есть некоторые отступы.

...