Реферат: API Spying
Возврат из функции
Возврат управления производит инструкция ret, имеющая четыре различные формы:
ret ret xxxh retf retf xxxh | ||
ПРИМЕЧАНИЕ Модификация retf предназначена для возврата из функции, которую вызвали из другого сегмента («дальним вызовом»). Ниже она не упоминается, так как, во-первых, в Windows вы её вряд ли встретите, во-вторых, с точки зрения реализации API Spying-а, она практически не отличается от ret. |
Задача, выполняемая ret*:
Удалить из стека адрес возврата.
(опционально) Удалить из стека указанное количество байт.
Передать управление по адресу возврата.
При этом все версии ret* предполагают, что адрес возврата находится на вершине стека, а байты, которые надо удалить (если надо) – сразу за ним.
Поскольку, как и при вызове, процессор ничего не знает о параметрах, удалять их из стека при возврате или нет – личное дело функции и вызывающего её кода. Распространены оба варианта: согласно формату вызова функций __cdecl за очистку стека отвечает вызывающий код, а согласно формату __stdcall этим занимается сама функция.
ПРИМЕЧАНИЕ Почти все стандартные API Windows придерживаются __stdcall, и большинство функций, экспортируемых из dll сторонних разработчиков, также следуют этому формату. |
Возвращаемое значение
Как и в случае с параметрами, про возвращаемые значения процессор тоже ничего не знает, и то, как именно и что именно вы будете возвращать, его не касается. Обычно возвращаемое значение передаётся через регистр eax или через пару eax:edx.
Состояние регистров до и после вызова
И этот вопрос остаётся полностью на совести программиста (в случае языка высокого уровня – программиста, писавшего компилятор). Если верить статье «Arguments Passing and Naming Conventions» в MSDN, для всех стандартных форматов вызова функций компилятор гарантирует сохранность регистров ESI, EDI, EBX и EBP. Это значит, что вызывающий код:
Может рассчитывать на то, что эти регистры не поменяются.
Не должен рассчитывать на регистры EAX, ECX, EDX, EFLAGS (с ним немного сложнее, очевидно, часть флагов всё-таки должна остаться неизменной, просто MSDN об этом не упоминает), а также на регистры MMX, FPU, XMM.
ПРИМЕЧАНИЕ А как же остальные регистры? Сегментные, управляющие, GDTR, LDTR, ….? С ними просто: если функция меняет какой-то из этих регистров, то, либо это документированный побочный эффект (например, ожидаемый результат) её вызова, либо автор функции очень, очень плохо пошутил… |
Проектирование
Система в целом состоит из четырёх частей:
Функция-шпион.
Механизм установки шпионов.
Функция сбора статистики.