- PVSM.RU - https://www.pvsm.ru -
Совсем недавно озадачился защитой приложений от перехвата системных api, решил поделится и обсудить то, к чему пришел. Многие из вас знают, что перехват системных api сводится к перенаправлению оригинальной функции в нужное место, благодаря этому можно модифицировать параметры функции, возвращать результат отличный от оригинала, хранить оригинальный вызов с параметрами и многое другое. Так как это теоретическая часть, примеры в статье будут сопровождаться псевдокодом.
Обычно используются следующие методы перехвата:
Можно перечислить следующие методы детектирования перехвата из usermode:
1. Сравнение начала функции перед ее вызовом с опкодами машинных инструкций:
//0x90 - nop
//0xE9 - jmp
//0xE8 - call
if (*mainFunc == 0xE9 || mainFunc == 0x90 || mainFunc == 0xE8 ...)
printf("Hook detected");
Метод статичный и легко обходится, более умными переходами.
2. Перечисленные методы перехвата — это модификация памяти, и они могут быть обнаружены по средствам crc checksum проверок, но api для чтения памяти тоже могут быть перехвачены и тогда будет возвращен ложный результат.
3. Порождать контролируемый процесс (с активной отладкой самого себя), с восстановлением важных api.
4. Перебор важных для нас api, используя таблицу экспорта в системных библиотеках, сравнивать дизассемблированную длину функции с оригинальной.
5. Восстановление модифицированных api по средствам копирования байтов из библиотеки, примерная схема такая:
— получение базы определенного модуля
— итерация экспорта
— получение RVA необходимой функции.
— преобразование RVA->FileOffset.
— чтение оригинала и запись в память.
— в некоторых случаях не забываем про релоки.
6. Просмотр таблицы импорта библиотеки и для каждой импортированной функции из другой системной библиотеки делать проверку на соответствие, если не совпадает так же читаем с диска и записываем в память.
7. Имитирование системных функций Nt / Zw по средствам syscall-ов, int2e в (старых версиях windows), таблица syscall-ов для всех систем, легко находится в гугле.
Остановимся на 7 методе так как Nt / Zw функции так же могут быть перехвачены, этот метод тоже далек от совершенства, но по моему мнению лучше из всего выше перечисленного.
Посмотрим на реализацию функции NtCreateFile в windows 7 sp1

происходит следующее:
— в еах лежит номер syscall-a.
— обнуляется ecx, (wow64 index?).
— в edx содержится указатель на параметры.
— далее вызов, корректировка стэка и возврат.
x64 вызов в win7 и win8

При помощи следующего x86 псевдокода «можно создать файл на диске».
//прототип функции NtCreateFile
typedef NTSTATUS (NTAPI * NTCREATEFILE) (OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER AllocationSize OPTIONAL,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN PVOID EaBuffer OPTIONAL,
IN ULONG EaLength);
unsigned char dNtCreateFile[] =
{0xb8,0x52,0x00,0x00,0x00,0x33,0xc9,0x8d,0x54,0x24,0x04,0x64,
0xff,0x15,0xc0,0x00,0x00,0x00,0x83,0xc4,0x04,0xc2,0x2c,0x00};
...
InitUnicodeString
InitializeObjectAttributes
...
DWORD oldp;
VirtualProtect(&dNtCreateFile, sizeof(dNtCreateFile), PAGE_EXECUTE_READ, &oldp);
auto func = (NTCREATEFILE) ((void*)dNtCreateFile);
Ntstatus = (func)(&fileHandle, DesiredAccess, ObjectAttritubes, ioStatusBlock, 0, FileAttributes, ShareAccess, CreateDisposition ,CreateOptions, Optional_Buffer, 0);
Данный псевдокод будет работать только на windows 7 sp1, однако dNtCreateFile можно формировать «динамично», используя метод из пункта 5, и тогда код с небольшими правками будет работать на всех системах начиная с winxp. Приветствуются любые размышления в комментариях, kernelmode — крайний случай.
Автор: Dinisoid
Источник [1]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/c-3/38505
Ссылки в тексте:
[1] Источник: http://habrahabr.ru/post/186334/
Нажмите здесь для печати.