Russian Qt Forum
Ноябрь 22, 2024, 22:23 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Что плохого в записи за пределы массива  (Прочитано 7097 раз)
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« : Сентябрь 21, 2015, 10:35 »

Привет, друзья!
Наткнулся на интересный пример в сети, решил, что будет хорошо его добавить сюда.
Имеется код:
Код
C++ (Qt)
#include <iostream>
 
int foo(){
   std::cout << "Hi! You are out of range :^)";
   return 1;
}
 
void bar(){
   int arr[500];
   arr[501] = reinterpret_cast<int> (&foo);
}
 
int main(){
   bar();
 
   return 0;
}
 

Видно, что в функции bar мы производим запись в ячейку с номером на 2 больше максимально допустимого.
Данный код я скомпилировал используя компилятор MinGW 4.92. Далее приводится результат работы (аттач 1).

Видно, что в коде происходит присвоение элементу массива arr с номером 501 адреса функции foo(). Никакого вызова функции foo() в коде нет. Однако, при исполнении программы, происходит вызов функции foo(), о чем свидетельствует появление в консоли строчки "Hi! You are out of range :^)".

Почему это происходит? Если мы посмотрим на устройство стека данной программы (аттач 2), то несложно заметить, что при попытке обращения к ячейке a[501] мы обращаемся в ячейку, которая отвечает за адрес возврата в место вызова функции bar. Переписав это значение адресом функции foo возврат состоится именно в неё! Важно отметить, что на разных системах с разными компиляторами стек может быть устроен по разному, соответственно, для воспроизведения данного примера может потребоваться заменить 501 на другое число чуть больше 499.
« Последнее редактирование: Сентябрь 23, 2015, 11:10 от xintrea » Записан
gil9red
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 1805



Просмотр профиля WWW
« Ответ #1 : Сентябрь 21, 2015, 19:14 »

Так вот как переполнение буфера может помочь получить доступ к системе Улыбающийся
Записан

Bepec
Гость
« Ответ #2 : Сентябрь 21, 2015, 20:26 »

Это всем давно известно. Более того, такой хак может применяется в случае необходимости доступа к приватным членам класса Улыбающийся
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Сентябрь 22, 2015, 09:59 »

Это всем давно известно. Более того, такой хак может применяется в случае необходимости доступа к приватным членам класса Улыбающийся
Прошу привести пример такого доступа
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #4 : Сентябрь 22, 2015, 10:04 »

Прошу привести пример такого доступа
Код
C++ (Qt)
#include <iostream>
 
class MyClass{
   int a;
   int b;
public:
   MyClass() : a(5), b(8) {}
};
 
int main(){
   MyClass my;
   int a[1];
   std::cout << a[1] << a[2] << '\n';
   return 0;
}
 
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Сентябрь 22, 2015, 10:29 »

Прошу привести пример такого доступа
Код
C++ (Qt)
#include <iostream>
 
class MyClass{
   int a;
   int b;
public:
   MyClass() : a(5), b(8) {}
};
 
int main(){
   MyClass my;
   int a[1];
   std::cout << a[1] << a[2] << '\n';
   return 0;
}
 
Это не работает напр на MSVC 2012, причем без разницы в каком порядке объявлены "my" и "a", тамошний компилятор первым на стеке помещает my - ну ему виднее. Вообще для таких трюков стек не нужен, просто
Код
C++ (Qt)
int * a = (int *) &my;
 
Обычно доступ (о котором говорил Верес которому удалось увильнуть от ответа) сводится к нахождению смещения нужного члена в отладчике и потом что-то типа
Код:
int * dst = (int *)((char *) &my + MAGIC_OFFSET);
Конечно это работает до первой перекомпиляции либы, тогда придется уточнять MAGIC_OFFSET.

Конечно никто не спорит что в любом случае это плохая практика, но можно ли сделать это легальным (с точки зрения языка) и независимым от платформы/компилятора?
Записан
Bepec
Гость
« Ответ #6 : Сентябрь 22, 2015, 16:29 »

Я не ускользал, я всё ж на форуме не живу)
Да, для этого нужно знать смещение, да, для разных компиляторов смещение будет разным и возможно порядок хаотичным, но на уже скомпилированной либе смещения статичны.

Средствами языка, без изменения исходников либы, невозможно. Хотя что считать средствами языка Веселый
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.132 секунд. Запросов: 23.