Я тестирую простое переполнение буфера в 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-го символа.
Почему они так сильно отличаются?
Вы должны изучить разборку. Оттуда вы увидите, что происходит точно.
Вообще говоря, следует учитывать две вещи:
Дополнение сделано компилятором для выравнивания переменных стека.
Относительное размещение переменных стека компилятором.
Первый пункт: ваш массив 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];
,
Вот бесстыдная ссылка на мой собственный ответ на подобный вопрос — пример изучения такого переполнения.
Неопределенное поведение, как вы обнаружили, не определено. Попытка объяснить это вообще не очень продуктивно.
В этом случае это почти наверняка связано с расположением вашего стека и байтов заполнения, вставляемых / между локальными переменными, которые различаются в зависимости от компилятора / системы.