Перехватывая API функции, мы увеличиваем наши возможности и граница им только наше воображение. Для прочтения данной статьи с максимальной пользой обязательны хоть начальные знания низкоуровневого программирования и знание архитектуры работы Windows.
Сегодня я вам расскажу наиболее действенную методику перехвата API функций – сплайсинг. Сплайсинг это подмена кода функции. Конечно, есть другой метод перехвата это редактирование таблицы импорта приложения. Рассказывать буду по порядку.
Когда вы пишете в своём приложении так
Function Func1(param*:type*):restype*;stdcall;external ‘libname.dll’;
Вы импортируете функцию статически. Адрес функции прописывается в таблице импорта вашего приложения
(допустим, что адрес нашей функции $7BC56010).
адрес значение
$00405F56 7BC56010
А при вызове функции происходит так
Push …
push …
call dword ptr
Следовательно, для перехвата функции нам надо только подменить значение по адресу $00405F56 на своё, а для вызова оригинальной функции получать адрес функции через GetProcAddress. Но приложение может также получить адрес функции через GetProcAddress и вызывать перехватываемую функцию минуя, перехватчик. Данный метод бесперспективен.
Идём дальше. Теперь я объясню технику сплайсинга. Наша функция находится по адресу $7C80B529 и допустим, что там такой код
7C80B529 8BFF mov edi, edi 7C80B52B 55 push ebp 7C80B52C 8BEC mov ebp, esp 7C80B52E 837D 08 00 cmp dword ptr ss:[ebp+8], 0
Для перехвата функции от нас требуется только переписать начальный код функции, так чтобы он передавал управление нашему обработчику. Для передачи управления нашему обработчику достаточно всего лишь одной инструкции jmp на абсолютный адрес. Эта инструкция займёт всего лишь 5 байт – сам опкод этой инструкции ($E9) и значение для прыжка. Это значение вычисляется так
v=0-(s-d)
s – Смещение следующей команды
d – Требуемый адрес для jmp, т.е. адрес обработчика
Если немного переделать эту формулу, то она будет выглядеть так
v=d-FunctionAddress-5
Теперь при каждом вызове целевой функции, всегда будет передаваться управление нашему обработчику. А как теперь вызвать оригинальную функцию. При установке перехвата нам надо сохранять первые 5 байт функции. Для вызова оригинала надо восстанавливать надо функции и вызывать ее, потом снова устанавливать перехват. Объявим структуру в которой будем сохранять первые 5 байт функции:
PFunctionRestoreData = ^ TFunctionRestoreData; TFunctionRestoreData = packed record Address:Pointer; val1:Byte; val2:DWORD; end;
С вами был Pirate, удачи!
Отредактировано Pirate (2013-09-10 23:01:42)