Привет народ. Помогите, дайте правильный кадр стека, а то я совсем замучался, везде приводят разные рисунки и структуры. Вот я сам накатал общий. Подправьте плиз, что где не так, и скажите какие размеры у полей которые постоянны. ------+------------------------------------------- размер|другой локальный буфер ------+------------------------------------------- размер|локальный буфер фиксированного размера ------+------------------------------------------- размер|служебная инф-ция (зависит от компилятора) ------+------------------------------------------- размер|адрес возврата ------+------------------------------------------- размер|адрес передаваемого параметра ------+------------------------------------------- размер|адрес передаваемого параметра ------+------------------------------------------- 1). Где должно быть поле, которые с сохранёнными регистрами при вызове функции? 2)И второй вопрос. Почему ишад ошибки на тех прогах в никсах у которых установлены флаги suid, sgid? А то я пока не селён в никсах. Спасибо.
1. Я не думаю, что есть понятие "правильного" кадра стека. Это скорее зависит от компилятора. Например, кадр может выглядеть так: 0: аргумент. 4: аргумент. 8: адрес возврата. C: адрес предыдущего стекового кадра. 10: локальная переменная. 14: локальная переменная. 14: сохраненный ebx 18: сохраненный esi 1С: сохраненный edi 2. Имелось в виду, что есть много ошибок в программах с установленным SUIG/SGID? В какой программе вы нашли ошибку? Кстати, раз уж речь зашла о стековых кадрах, кто-нибудь знает, откуда они появились? Я подозреваю, что это пережиток 16битного режима, где нельзя было адресоваться относительно sp. Сейчас такой необходимости нет, адресация [esp] разрешена. Получается, что стековый кадр удобен только в случае, когда пишешь на ассемблере и в ф-ии много локальных переменных.
suid - идентификатор суперпользователя, sgid - идентификатор группы суперпользователя. Программы, у которых установлены данные флаги, позволяют запускать их обычным пользователям с правами администратора. Например, форматирование дискеты в линукс операция привелигерованная, и может выполняться только с правами администатора. В результате, если найти в такой программе ошибку переполнения, можно сделать так, что программа с правами администратора станет выполнять произвольный код, например придостовляющей доступ к оболочке командного интерпретатора - shell. Отсюда и пошло слово шеллкод.
Вот кусок из книги Касперского Атака на счётчик цикла f(char *dst, char *src) { char buf[xxx]; int a; intb; ... b = strlen(src); ... for(a = 0; a<b; a++) *dst++=*src++; } И вот что он пишет. Если переполнение буфера buf произоёдёт после вызова strlen, переменная b будет жестоко затёрта и наш цикл вылетит далеко на пределы src и dst А теперь вопрос. Как вообще может затереться b если buf объявлена перед ней. И значит при переполнении мусор полезет к старшим адресам, а переменная b находиться ниже.
Потому что Intel расширили возможности адресации в 32битном режиме. Код, которым кодируется регистр esp (100b) используется для указания, что в инструкции есть дополнительный байт -- SIB. Этот байт позволяет создавать инструкции типа 'command reg, [base + index * {1, 2, 4, 8} ]'. В результате, единственная возможность закодировать адресацию по esp -- кодировать его в SIB, т.к. код esp в байте MODRM сам по себе используется для указания наличия SIB. По этой же причине регистр esp не может быть индексным регистром, т.к. в случае адресации типа [esp] в байте SIB необходимо указать, что индексный регистр отсутствует. Например, команда 'mov eax, [esp]' кодируется как 'mov eax, [esp + esp * 1]'. Процессор игнорирует esp в качестве индексного регистра, поэтому получается 'mov eax, [esp]'. Но обо всех этих деталях лучше почитать в Intel Manual 2A. Там в самом начале рассмотрен формат инструкции.
Ну, тут зависит какой код выполнить после b = strlen(src); Код (Text): std lea edi, buff lea esi, buff1 repe movsb то запись будет осуществляться в сторону младших адресов А с другой стороны, надо посмотреть, как конкретно кампилятор расставит переменные
я посмотрел. Вот так -------- return addres ---------- ... --------- buf[xxx] ---------- int a --------- int b -------- я так думал что переполнении всегда идёт к старшим адресам то есть к адресу возврата, а что мона в другую сторону?
Народ, ну помогите, объясниите, в чём прикол. Почему он так пришет? Если переполнение буфера buf произоёдёт после вызова strlen, переменная b будет жестоко затёрта и наш цикл вылетит далеко на пределы src и dst Я не понимаю. Как может b затереться. Плиз
ajak Вообще Subrealist Вам уже объяснил. Я только повторю. Не знаю, где Вы смотрели, но MSVC6.0 размещает a и b в стэке по адресам, старшим, чем адрес buf[xxx]. О возможности переполнения "в обратную сторону" Subrealist тоже упомянул, но такое встречается реже.