9 сентября 2012 г.

Ответ на задачку №15

Ответ на задачку №15.

Для начала я кратко пробегусь по явно неверным ответам:

VirtualProtect пишет в OldProtectionCode прежде чем читает новое значение
Третий аргумент передаётся в VirtualProtect по значению, поэтому любые изменения четвёртого аргумента во время работы функции не влияют на третий аргумент.

Если мы под отладчиком, и на начало функции ATargetFunction поставлена точка останова, то там код уже изменён, дебажий хук стоит.
Автор ответа сам же и указал: "что может сломаться - непонятно". Точка останова просто будет убрана (перезаписана JMP).

мне очень любопытно, что будет если вашу функцию натравить на нея самою. Не выдернет она у себя из под ног право на исполнение себя самой?
Надо понимать, что "задачки" возникают исключительно из практики. Кто будет ставить хук на функцию установки хука?

что будет, если скармливается функция размером меньше 8 байт, стоящая на самом конце стpаницы, и следующей стрaницы просто-таки не существует ( ну или guard page, etc) ?
Мне кажется, что автор пропустил
const
  MaxPossibleSize = 8;
и
размер ATargetFunction больше 8-ми байт

FlushInstructionCache(GetCurrentProcess, ATargetFunction, MaxPossibleSize)
сказал MSDN :)
Это была маленькая ловушка для отвлечения внимания. Отсутствие FlushInstructionCache - первое, что должно броситься в глаза. Однако вот вопрос: что будет, если мы не вызовем FlushInstructionCache? Это значит, что потенциально в кэше процессора будет находиться старая команда, до её перезаписи. Поэтому при ближайшем вызове ATargetFunction будет вызван не наш JMP, а её оригинальный код. Понятно, что это не приведёт к Access Violation, а просто не сработает хук. Хотя отсутствие FlushInstructionCache - это действительно ошибка, но это не проблема этой задачки.

Собственно, правильный ответ был назван многими, хотя никто не догадался о самом очевидном сценарии. Итак, действительно, изменение атрибутов защиты 8-ми байт кода изменит атрибут защиты не только этих восьми байт, но и целой страницы памяти (обычно - 4 кб), потому что одна страница памяти является минимальной единицей для системной памяти. Чем же это грозит? Дело в том, что мы можем устанавливать хук на системную функцию. А эта функция... может быть расположена рядом с самой VirtualProtect! Иными словами, первый вызов VirtualProtect изменит атрибут защиты страницы с целевой функцией (а заодно - и с самой VirtualProtect) с PAGE_EXECUTEREAD на PAGE_READWRITE, что, конечно же, позволит нам записать туда JMP, но второй вызов VirtualProtect вылетит с Access Violation, потому что попытается выполнить код со страницы с атрибутами PAGE_READWRITE, где нет права на выполнение кода (см. также).

Исправление заключается в изменении атрибута на PAGE_EXECUTEREADWRITE.

2 комментария :

  1. >>> хотя никто не догадался о самом очевидном сценарии
    Как никто, а некий FLABER один в один описал. В третьем комментарии. А в первом было высказано предположение что скорее всего это PAGE_EXECUTE_READWRITE

    ОтветитьУдалить
  2. Под "самым очевидным сценарием" подразумевалась установка хука на функцию ядра. А на проблему атрибутов защиты указало несколько человек.

    ОтветитьУдалить

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и (опционально) ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.