45821 (API Spying)

2016-07-31СтудИзба

Описание файла

Документ из архива "API Spying", который расположен в категории "". Всё это находится в предмете "информатика" из , которые можно найти в файловом архиве . Не смотря на прямую связь этого архива с , его также можно найти и в других разделах. Архив можно найти в разделе "рефераты, доклады и презентации", в предмете "информатика, программирование" в общих файлах.

Онлайн просмотр документа "45821"

Текст из документа "45821"

API Spying

Сергей Холодилов

Я открываю свойства растений и трав..

Борис Гребенщиков

Словосочетанием «API Spying» называется слежение за вызовами функций API некоторым приложением. То есть, каждый факт вызова этим приложением выбранных функций каким-то образом фиксируется, например, добавляется запись в лог.

ПРИМЕЧАНИЕ

Для ясности назовём «некоторое приложение» исследуемым приложением, а «выбранные функции» – отслеживаемыми функциями.

Зачем это нужно

API Spying может использоваться на одном из этапов исследования программы, логику работы которой вы пока не до конца понимаете. Хотя эта технология и не позволяет получить детальную информацию, она может значительно сузить область последующих этапов исследования, сконцентрировав ваше внимание на тех вызовах, которые происходят в ключевые моменты работы программы.

На первый взгляд может показаться, что задача лучше решается с помощью перехвата API, так как он даёт возможность не только отследить вызов, но и изучить/изменить параметры и возвращаемое значение, или даже полностью переписать функцию.

Действительно, перехват API – замечательная и часто упоминаемая техника (на данный момент на RSDN этой теме посвящены три статьи), позволяющая довольно глубоко изучить исследуемое приложение, но это и гораздо более трудоёмкое решение. Даже если реализации функций будут почти пустыми (только запись в лог и вызов оригинальной функции), ваш код будет примерно таким:

typedef int (__stdcall* Function1_type)(int i);

Function_type _Function1;

// Обёртка, логирующая вызовы

int __stdcall MyFunction1(int i)

{

printf("MyFunction1\n");

return _Function(i); // Вызов оригинальной функции

}

...

// Перехват всех функций

void HookThemAll()

{

...

// Перехват функции _Function1, экспортируемой some.dll

HookIt("some.dll", "_Function1@4", MyFunction1, &_Function1);

...

}

ПРИМЕЧАНИЕ

Это приблизительный код, используемый при перехвате через таблицу импорта; другие варианты перехвата в данном случае не имеют существенных преимуществ.

То есть, для каждой функции придётся:

определить тип;

определить переменную;

написать обёртку;

добавить строчку в HookThemAll.

Это, конечно, довольно простые операции… Но представьте, что таким образом вам нужно перехватить несколько сотен функций. А если не у всех функций известны прототипы? А если некоторые dll загружается динамически, и вы пока даже не знаете, какие их функции используются приложением? А если после того, как вы всё успешно перехватите и просмотрите получившиеся логи, станет понятно, что для детального понимания работы приложения нужно было перехватить всего две функции и изучить их параметры :) ?

Когда все эти вопросы встали передо мной, я занялся API Spying-ом.

API Spying не исключает перехвата API, но эти методики используются находятся на разных стадиях анализа программы. Сначала при помощи API Spying-а определяется несколько наиболее интересных функций, потом, если необходимо, эти функции перехватываются и изучаются «в более тесном контакте».

Постановка задачи

В самом общем виде задача выглядит так:

Необходимо получать информацию о фактах вызова выбранных функций исследуемым приложением.

Для получения статистики не обязательно заранее знать имена функций, которые будут вызываться приложением. Тем более, не нужно знать их прототипы.

Сбор статистики для любого (в том числе заранее неизвестного) количества функций из любых (в том числе, из загружаемых динамически) модулей не должен представлять трудностей.

Работоспособность исследуемого приложения не должна нарушаться.

Формулировка ТЗ

Логически разовьём требования, высказанные в постановке задачи:

Мы рассматриваем только программные реализации. Это значит, что статистика собирается программно, и этим занимается наш код.

Поскольку при каждом вызове отслеживаемых функций управление должно передаваться нашему коду, все отслеживаемые функции нужно перехватить (тем или иным способом; подробное рассмотрение способов перехвата API выходит за рамки статьи). Нашу функцию, которой в результате перехвата будет передаваться управление, назовём функцией-шпионом (терминология моя, сожалею, если не прав).

Чтобы вести статистику вызовов и не нарушать работу приложения, функция-шпион должна определить, какую именно отслеживаемую функцию собиралось вызвать исследуемое приложение. Единственный способ реализовать это – сопоставить каждой отслеживаемой функции свою функцию-шпиона, «знающую», как минимум, адрес оригинала.

По возможности, присутствие функции-шпиона не должно влиять на выполнение отслеживаемой функции. Это получается не всегда, разумные исключения описаны ниже, в разделе «Почему приложение может перестать работать».

Так как количество отслеживаемых функций может быть велико или заранее не известно, функции-шпионы должны генерироваться автоматически в процессе исполнения.

Несколько дополнительных пожеланий:

Автоматически генерировать сложные функции-шпионы непросто. :) Их даже писать на ассемблере замаешься... Хорошо бы подсчёт статистики взял на себя кто-то другой.

ПРИМЕЧАНИЕ

Вы классно знаете ассемблер, и считаете, что это пара пустяков? Возможно, вы не учли, что код функций будет расположен в произвольном месте адресного пространства и что (забегая вперёд; но вы-то это всё должны понимать) функции не могут модифицировать стек и регистры. Если и это для вас не проблема, то, во-первых, примите моё искреннее восхищение (без шуток!), во-вторых, прочитайте следующий пункт. :)

Автоматическая генерация подразумевает выделение памяти для кода функций, а, так как их может быть много, желательно чтобы функции были короткими. Поэтому, опять же, хорошо бы подсчёт статистики взял на себя кто-то другой.

И несколько ограничений:

Эта реализация поддерживает только Intel x86-совместимые процессоры.

Для работы функции-шпиона от ОС требуется только одно: она должна позволять исполнять динамически сгенерированный код. Это условие соблюдается во всех версиях Windows и, скорее всего, в подавляющем большинстве остальных ОС общего пользования. Но, поскольку нам необходим ещё и способ перехвата, ограничимся линейкой Windows NT/2000/XP. Используя другие способы перехвата, можно реализовать API Spying для других ОС.

Неизвестно, как на исполнение сгенерированного кода будут реагировать антивирусы. Возможно, они будут недостаточно толерантны. :)

СОВЕТ

О подобных ограничениях лучше не забывать и в реальных проектах, так как иначе выполнить ТЗ будет практически невозможно.

Почему приложение может перестать работать

Проблема заключается в том, что (увы!) статистика собирается не магически, её собирает наш код, внедрённый в исследуемое приложение. У этого простого факта есть три неприятных следствия:

При добавлении сбора статистики изменится скорость работы функций. Обычно это ни на что не влияет, но если в середине критичного к скорости выполнения кода мы неожиданно (для приложения и его автора) начнём запись в файл, может получиться плохо. Например, FPS упадёт раз в десять :) Но FPS – это не страшно, страшно, если вы исследуете многопоточное приложение c некорректно написанной синхронизацией, и изменение времени выполнения потоков приведет к дедлокам, падениям или просто непонятному поведению.

Помимо процессорного времени, наш код использует и другие ресурсы: память, стек, (возможно) окна, объекты ядра (файлы, события, и т.п.) и другие. В некотором фантастическом случае это может стать последней каплей, приводящей к исчерпанию доступных ресурсов потоком, процессом, или даже системой.

Если автор приложения решил позаботиться о защите своего детища, он вполне в состоянии засечь наши манипуляции, обидеться (он же не знает, что мы ничего плохого не хотели) и сделать какую-нибудь бяку. Например, откажется работать, или станет работать неправильно, или отформатирует случайно выбранный диск…

Все эти следствия в той или иной степени свойственны любой программной реализации API Spying-а, и ни в одной из этих ситуаций я не могу посоветовать вам ничего хорошего. Можно только попытаться уменьшить степень влияния и избежать столь пагубных последствий.

Предпроектные исследования: функции в Intel x86

Как вы уже, наверное, поняли, нам предстоит динамическая генерация кода функций-шпионов. Хотя ничего особо сложного в этом не будет (они действительно очень простые), небольшое теоретическое введение поможет вам понять (а мне – объяснить), как должна быть написана функция-шпион, чтобы вызов отслеживаемой функции завершился без помех.

Вызов

С точки зрения процессора вызов функции выполняет инструкция call, имеющая несколько разных форм:

call xxxxxxh

call xxxxh:xxxxxxh

call eax

call [eax]

...

Она сохраняет в стеке адрес, по которому нужно передать управление после окончания функции, и передаёт управление на начало функции.

Передача параметров

Процессор Intel x86 ничего не знает о параметрах вызываемых функций, поэтому механизм передачи параметров может быть произвольным, главное чтобы вызывающий и вызываемый код договорились о нём заранее. Мест, где можно сохранить параметры, не так уж и много: либо в регистрах, либо в стеке, либо часть там, а часть там.

ПРИМЕЧАНИЕ

Конечно, можно передавать параметры по ссылке или по значению, в прямом порядке или в обратном, но это для нас не важно, важно только то, где передаваемая информация (параметры или их адреса) находится.

Передача параметров через регистры используется в основном в двух случаях:

Компилятором для оптимизации.

Ассемблер-программистом из лени или в погоне за производительностью. Чтобы достать параметры из стека, надо написать несколько дополнительных команд, а в регистрах они сразу под рукой.

В большинстве остальных случаев параметры передаются через стек. При этом вызов функции выглядит примерно так:

push ... ; Параметр

push ... ; Ещё один параметр

push ... ; И последний параметр

call xxxxxh ; Вызов

А стек к моменту начала выполнения функции – так:

Рисунок 1. Состояние стека в начале выполнения функции.

Возврат из функции

Возврат управления производит инструкция 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, ….? С ними просто: если функция меняет какой-то из этих регистров, то, либо это документированный побочный эффект (например, ожидаемый результат) её вызова, либо автор функции очень, очень плохо пошутил…

Проектирование

Свежие статьи
Популярно сейчас
Как Вы думаете, сколько людей до Вас делали точно такое же задание? 99% студентов выполняют точно такие же задания, как и их предшественники год назад. Найдите нужный учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Нашёл ошибку?
Или хочешь предложить что-то улучшить на этой странице? Напиши об этом и получи бонус!
Бонус рассчитывается индивидуально в каждом случае и может быть в виде баллов или бесплатной услуги от студизбы.
Предложить исправление
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
5138
Авторов
на СтудИзбе
443
Средний доход
с одного платного файла
Обучение Подробнее