Подтвердить что ты не робот

Stack Smashing попытка дать segfault

Я пытаюсь сделать пример из Smashing the Stack for Fun and Profit на C, но я как бы застрял в точке, следующий код (у меня 64-разрядная машина с 64-битным Ubuntu):

int main()
{
    int x;

    x = 0;
    func(1,2,3);
    x = 1;
    printf("x is : %d\n", x);
}

void func(int a, int b, int c)
{
    char buffer[1];
    int *ret;

    ret = buffer + 17;
    (*ret) += 7;
}

Вышеприведенный код работает нормально, и при возврате строки x=1 не выполняется, но я не могу понять логику, стоящую за ret = buffer + 17;, не должно быть ret = buffer + 16;, т.е. 8 байт для буфера и 8 для сохраненный базовый указатель на стеке.

Во-вторых, я понимаю, что char buffer[1] принимает 8 байтов (из-за 64-битной дуги) и если я увеличу этот буфер, скажем buffer[2], все равно тот же код должен работать нормально, НО этого не происходит, и он начинает выдавать ошибку seg.

С уважением, Ньюман

4b9b3361

Ответ 1

'char' для каждой используемой архитектуры составляет 8 бит, независимо от того, является ли это 8-битным микро, 16-битным микро, 32-битным ПК или 64-битным новым ПК. Int, с другой стороны, имеет тенденцию быть размером слова.

Порядок, который локальные жители помещают в стек, может быть специфичным для реализации. Я предполагаю, что ваш компилятор помещает "int * ret" в стек до "char buffer 1". Итак, чтобы перейти к обратному адресу, нам нужно пройти через char buffer 1 "(1 байт)," int * ret "(8 байтов) и сохраненный базовый указатель (8 байтов) для всего 17 байтов.

Здесь описание фрейма стека на 64-разрядной версии x86: http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-035-computer-language-engineering-spring-2010/projects/x86-64

Ответ 2

Проделайте разборку в gdb (дизассемблируйте, stepi, nexti) и посмотрите на регистры на каждом этапе (информационные регистры).

Здесь вы можете выполнить разборку:

gdb ./myprogram
break main
run
display/4i $eip
stepi
stepi
...
info registers
...

Вы также должны знать (возможно, вы уже знаете, что у вас есть часть его работы), что во многих дистрибутивах защитник стека включен по умолчанию в gcc. Вы можете отключить его вручную с помощью -fno-stack-protector.

Ответ 3

С большим количеством этого разбитого материала, ваш лучший друг gdb. Поскольку вы уже сталкиваетесь, вы уже пишете память, которую вы не должны быть (хороший знак). Более эффективный способ сделать это правильно - это изменить обратный адрес в другом месте, где действительный адрес (например, на адрес func или на какой-либо шелл-код у вас есть). Отличный ресурс, который я бы рекомендовал, - это Handcoder Handbook, но поскольку вы находитесь в 64-битной архитектуре, многие примеры требуют бит работы, чтобы идти.

Ответ 4

Помимо (или еще лучше) выполнения отладчика, вы также можете использовать конструкцию printf% p для печати адресов ваших переменных, например:

printf("buf: %p\n", buffer); //&buffer[0] works too; &buffer works for an array
printf("ret: %p\n", &ret):
printf("a:   %p\n", &a);

Печать адресов различных вещей может дать большое представление о том, как ваш компилятор/реализация организует вещи в фоновом режиме. И вы можете сделать это прямо из C-кода тоже!