Когда-то мы обсуждали, почему все функции Windows начинаются с бессмысленной инструкции
MOV EDI, EDI
. Ответ заключался в том, что эта инструкция использовалась как двухбайтовый NOP
, что позволяло безопасно заменить её на инструкцию перехода JMP $-5
, что позволяло применять различные исправления к работающей системе (такой метод не подходит для тех исправлений, которые изменяют структуры данных или включают взаимодействие между процессами).Но вы могли заметить, что в 64-битной Windows эти бессмысленные инструкции исчезли. Значит ли это, что метод мёртв?
Нет, этот способ всё ещё применяется. Но в 64-битной Windows точка для внедрения реализована иначе.
Идея состоит в том, что нам не нужно вставлять в каждую функцию бессмысленную двухбайтовую инструкцию
NOP
, если первая (настоящая) инструкция функции уже является двухбайтовой инструкцией (или длиннее). В этом случае эта инструкция сама по себе может служить точкой для внедрения.Случай, когда первая инструкция функции занимает два байта или больше, является наиболее распространенным. В x86-64 осталось всего несколько однобайтовых инструкций. Вот те, с которыми вы можете столкнуться в коде, сгенерированном компилятором пользовательского режима:
PUSH R |
LEAVE |
CWDE |
INT 3 |
POP R |
RET |
CDQ |
NOP |
R
— 64-битная версия одного из восьми именованных (не пронумерованных) регистров.Некоторые из этих инструкций не могут стоять в начале функции:
LEAVE
не имеет смысла, потому что она изменяет регистр, который мы (как вызываемый) должны сохранять.CWDE
иCDQ
не имеют смысла, потому что они используютRAX
в качестве входного регистра, но этот регистр не определен при входе в функцию.NOP
можно просто опустить.- Начало функции с
POP
запрещено Win32 ABI: адрес возврата должен оставаться в стеке.
PUSH
: если функция вносит в стек какие-либо регистрыR8
или выше, компилятор может поставить эти инструкции в начало функции, поскольку внос в стек регистра с верхним номером является двухбайтовой инструкцией. Либо же компилятор может перекодировать инструкцию с избыточным префиксомREX 0x48
. Наконец, в качестве альтернативы компилятор может сохранить регистр в домашнем пространстве (home space), для чего используется многобайтовая инструкцияMOV [RSP+n], R
.RET
: это происходит, если функция пуста и не возвращает значения. Тогда компилятор может изменить её на 3-байтовыйRET 0
или 2-байтовыйREPZ RET
.
INT 3
(программная точка останова).Один из вариантов — использовать альтернативную двухбайтовую кодировку
CD 03
(INT nn
, где nn
= 3). Однако код, который установил INT 3
, может полагаться на то, что это именно однобайтовая инструкция, потому что он намеревается исправить её с помощью однобайтового NOP
, или он намеревается обработать исключение "точка останова", перешагнув код инструкции путём увеличения указателя инструкции на 1.Вместо этого компилятор перестраховывается и начинает функцию с двухбайтового
NOP
, который закодирован как XCHG AX, AX
- и, действительно, отладчик Microsoft именно так его и дизассемблирует.Бессмысленная инструкция
MOV EDI, EDI
исчезла. И в большинстве случаев компилятор может жонглировать командами так, что вы даже не заметите, что он устроил так, чтобы первая инструкция вашей функции была многобайтовой инструкцией. Единственный случай, когда компилятор терпит неудачу, это если первой инструкцией вашей функции является INT 3
, но тогда компилятор вставляет бессмысленную инструкцию XCHG AX, AX
, также известную как двухбайтная команда NOP
.
Комментариев нет:
Отправить комментарий
Можно использовать некоторые HTML-теги, например:
<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>
Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку.
Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.
Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.
Примечание. Отправлять комментарии могут только участники этого блога.