Конструкция компилятора — переполнение буфера в C ++ на 3 компьютерах

Я тестирую простое переполнение буфера в c ++. Примером является тест, в котором при отсутствии проверок злонамеренный пользователь может перезаписывать переменные, используя переполнение буфера.

В примере определяется буфер, а затем переменная, это означает, что для буфера должно быть выделено место, а затем — для переменной. Пример читает из cin в буфер длиной 5, а затем проверяет, установлена ​​ли переменная администратора что-либо, отличное от 0, если это так, пользователь концептуально получил доступ администратора.

#include <iostream>
using namespace std;

int main()
{
char buffer[5];
int admin = 0;

cin>>buffer;
if(strcmp(buffer,"in") == 0)
{
admin = 1;
cout<<"Correct"<<endl;
}
if(admin != 0)
cout << "Access" << endl;
return 0;
}

У меня есть 3 машины, 1 Windows и 2 системы Linux.

Когда я проверяю это в Windows (CodeBlocks), это работает (логично)
ввод более 5 символов переполняет и перезаписывает admin байты переменной

Теперь моя первая система Linux также работает, но только когда я ввожу 13 символов, это связано с различными компиляторами и как они выделяют память для программы?

Моя вторая машина Linux не может переполниться вообще. Это даст ошибку дампа только после 13-го символа.

Почему они так сильно отличаются?

1

Решение

Вы должны изучить разборку. Оттуда вы увидите, что происходит точно.

Вообще говоря, следует учитывать две вещи:

  1. Дополнение сделано компилятором для выравнивания переменных стека.

  2. Относительное размещение переменных стека компилятором.

Первый пункт: ваш массив char buffer[5]; будет дополнено так int admin; будет правильно выровнен по стеку. я будет ожидать он обычно дополняется до 8 байтов на обоих x86 или же x64 и так 9 символов для перезаписи. Но компилятор может делать по-разному, в зависимости от того, что он считает нужным. Тем не менее, это появляется что Windows и Linux машины x86 (32 бит).

Второй момент: компилятору не требуется помещать переменные стека в стек в порядке их объявления. На Windows и первом компьютере Linux компилятор действительно помещает char buffer[5]; ниже int admin;, так что вы можете переполнить его. На второй машине с Linux компилятор выбирает размещение в обратном порядке, вместо того, чтобы переполняться в int admin;портишь стек фрейма вызывающего main() после написания за пределами отведенного для char buffer[5];,

Вот бесстыдная ссылка на мой собственный ответ на подобный вопрос — пример изучения такого переполнения.

1

Другие решения

Неопределенное поведение, как вы обнаружили, не определено. Попытка объяснить это вообще не очень продуктивно.

В этом случае это почти наверняка связано с расположением вашего стека и байтов заполнения, вставляемых / между локальными переменными, которые различаются в зависимости от компилятора / системы.

1