Как подменить стек?
От: Алексей Ширшов Россия http://wise-orm.com
Дата: 21.07.03 03:52
Оценка: 105 (5)
Статья:
Как подменить стек?
Автор(ы): Алексей Ширшов
Дата: 01.04.2003
Переполнение стека – одна из самых сложных ошибок, восстановление после которой практически невозможно. По существу эта ошибка считается фатальной, и единственное, что может сделать приложение, обрабатывая ее, выдать какое-либо сообщение об ошибке или записать его в лог. Никакой серьезной работы проделать невозможно, т.к. обработчик вызывается на уже «умирающем» стеке. В этой статье рассматривается, как подменить текущий стек на свой собственный. Более подробно цели описаны в следующем разделе. Все материалы относятся к операционной системе Windows 2000 и WindowsXP.


Авторы:
Алексей Ширшов

Аннотация:
Переполнение стека – одна из самых сложных ошибок, восстановление после которой практически не возможно. По существу эта ошибка считается фатальной, и единственное, что может сделать приложение, обрабатывая ее, выдать какое-либо сообщение об ошибке или записать его в лог. Никакой серьезной работы проделать невозможно, т.к. обработчик вызывается на уже «умирающем» стеке. В этой статье рассматривается, как подменить текущий стек на свой собственный. Более подробно цели описаны в следующем разделе. Все материалы относятся к операционной системе Windows 2000 и WindowsXP.
Re: Как подменить стек?
От: Valerio Россия linkedin.com/in/boronin
Дата: 21.07.03 04:18
Оценка: 9 (1)
АШ>Статья:
АШ>Как подменить стек?

статья хорошая!

в качестве мелкого замечания-дополнения по своей области:
наверное стоит отметить что в статье речь не идет о режиме ядра?

1. в режиме ядра в НТ стек для обработки IRP ограничен обычно 12К
(вообще задается ключом в реестре для IO Manager) и с исключениями
для ловли stack overflow лучше не пользоваться

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

пример — различные фильтры, когда верхний драйвер совершенно не ждет
такой пакости как измененный стек от нижнего

конкретный пример — Norton Antivirus довольно долго использовал
технику подмены стека и практически все 3d party file system filters
не работали вместе с ним поэтому тут надо быть предельно акуратным

2. подменить же стек в 9х (на уровне ядра) можно очень легко:
есть такая замечательная вещь как _Call_On_My_Stack
... << RSDN@Home 1.1 beta 1 >>
Valery A. Boronin, RSDN Team, linkedin.com\in\boronin
R&D Mgmt & Security. AppSec & SDL. Data Protection and Systems Programming. FDE, DLP, Incident Management. Windows Filesystems and Drivers.
Re[2]: Как подменить стек?
От: Alexey Shirshov Россия http://wise-orm.com
Дата: 21.07.03 05:16
Оценка:
Здравствуйте, Valerio, Вы писали:

[]

Хорошие коментарии.
Если есть желание помочь в создании второй, более полной версии статьи, можемь поговорить об этом по мылу.
Есть?
Re: Как подменить стек?
От: Аноним  
Дата: 27.04.06 10:18
Оценка:
Здравствуйте, Алексей Ширшов, Вы писали:
>Изначально система не передает (commit) весь стек потоку, так как весь он может и не понадобится; передаются только первые две его страницы. Для последней из передаваемых изначально станиц устанавливается флаг PAGE_GUARD. По мере разрастания дерева вызовов система передает все больше страниц стека физической памяти. Последняя страница «обычного» стека никогда не передается и всегда остается зарезервированной.
Т.е. "сторожевая" страница (т.е. страница, при обращении к которой происходит увеличение стека) у нас одна. Теперь рассмотрим ситуацию. У меня в C-функции есть локальный массив эдак килобайт на 100 (а чего мелочиться — проблем с new/delete меньше, по выходу из функции массив автоматически будет удален). Это явно больше одной "сторожевой" страницы. И, допустим, я начинаю обрабатывать этот массив с середины (чтобы "промахнуться" мимо "сторожевой" страницы и попасть в не-commited память). Что, я получу GPF (general protection fault)? Но в реальности так не происходит (вроде бы). Вопрос — как система справляется с такой ситуацией?
ЗЫ — книжку Рихтера очень уважаю, но читал давно, так что могу уже чего-то не помнить.
Re[2]: Как подменить стек?
От: Pavel Dvorkin Россия  
Дата: 28.04.06 05:13
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Т.е. "сторожевая" страница (т.е. страница, при обращении к которой происходит увеличение стека) у нас одна. Теперь рассмотрим ситуацию. У меня в C-функции есть локальный массив эдак килобайт на 100 (а чего мелочиться — проблем с new/delete меньше, по выходу из функции массив автоматически будет удален). Это явно больше одной "сторожевой" страницы. И, допустим, я начинаю обрабатывать этот массив с середины (чтобы "промахнуться" мимо "сторожевой" страницы и попасть в не-commited память). Что, я получу GPF (general protection fault)? Но в реальности так не происходит (вроде бы). Вопрос — как система справляется с такой ситуацией?


При каждом входе в С — функцию библиотека RTL вызывает функцию _checksp (вроде так называется, не уверен), которая обстреливает стек, делая обращения к страницам на весь размер локальной памяти функции и тем самым перемещая PAGE_GUARD.

А>ЗЫ — книжку Рихтера очень уважаю, но читал давно, так что могу уже чего-то не помнить.


У него об этом есть.
With best regards
Pavel Dvorkin
Re[3]: Как подменить стек?
От: MShura  
Дата: 28.04.06 10:28
Оценка: 1 (1) +1
PD>При каждом входе в С — функцию библиотека RTL вызывает функцию _checksp (вроде так называется, не уверен), которая обстреливает стек, делая обращения к страницам на весь размер локальной памяти функции и тем самым перемещая PAGE_GUARD.

Уточнения:
Перемещение PAGE_GUARD происходит автоматически, если размер локальных переменных вызываемых функции меньше размера "строжевой" страницы. В этом случае нет никакого дополнительного "обстрела" стека.
Если размер локальных переменных в какой-то (вашей или библиотечной) функции превышает размер "строжевой" страницы (4К) есть вероятность обратиться за её пределы прежде чем PAGE_GUARD будет передвинута. Чтобы этого не произошло компилятор вставляет в начало такой функции функцию "обстрела" стека. Называться она может по разному (например _alloca_probe или _chkstk) и реализована обычно в файле CHKSTK.OBJ.
_checksp — это функция для проверки "соглашения о вызовах", вставляется после вызова каждой функции если определен _DEBUG.

Такое поведение компилятора может настраиваться ключами компиляции.
Re[4]: Как подменить стек?
От: Pavel Dvorkin Россия  
Дата: 28.04.06 11:44
Оценка:
Здравствуйте, MShura, Вы писали:

Спасибо за уточнение. Действительно, давно уже я этим занимался, забыл детали.
With best regards
Pavel Dvorkin
Re: Как подменить стек?
От: Аноним  
Дата: 08.12.07 16:52
Оценка:
Здравствуйте, Алексей Ширшов, Вы писали:

АШ> Команда RETN

АШ> Действует также как и pop, однако операндом для нее неявно служит регистр eip – extended instruction pointer (указатель команд). С помощью этой команды вы можете изменять содержимое указателя команд, хотя явных инструкций для его изменения нет.

А как же инструкция JMP? Или её действия можно отнести к неявным?
Вот инструкции получения текущего значения eip, кажется, действительно нет (обынчно используют связку вроде call L1; L1: pop eax; ).
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.