Буквально вчера я увидел в интернете интересную новость о том, что появилась зло-программа, которая после заражения компа скачивает пиратскую версию «Антивируса Касперского» и с ее помощью уничтожает всех конкурентов. Оригинальное решение :). Мы много раз слышали о том, что вирусы пытаются обмануть антивирусы, но такая странная дружба на моей памяти происходит впервые. Эта новость подвигла меня на разговор о том, как можно обмануть антивирус. Ларчик-то достаточно просто открыть (точнее, закрыть ;)). 

Вырубаем

Многие хакеры стремятся написать такой код вируса, трояна или другого зла, чтобы анализатор антивируса не смог его найти. Самое простое и эффективное решение кроется в отключении сервиса антивируса. Не знаю, как «Касперский» (давно его не юзал), а Symantec и Dr. Web работают как сервисы, а значит, чтобы наш зло-код спокойно работал в системе, не боясь антисредств, достаточно просто отключить соответствующий сервис, и никто уже не наш не остановит. Самое поразительное, что можно создавать сервисы, которые невозможно вырубить, но известные мне антивирусы почему-то легко отключаются. Это вполне логично, ведь анализаторы иногда ошибаются (сам с таким встречался), и тогда пользователь должен иметь возможность отключить слишком умный антивирус и позволить продолжить работу с программами, которые анализатор воспринял как зло. 

Еще пример. Когда-то мы писали о том, что сервис Messenger небезопасен и подвержен атаке флудом, поэтому его начали отключать. Но кто мешает нам написать небольшую программу, которая будет запускать сервис на компьютере жертвы, чтобы потом его можно было атаковать флудом через NET SEND :)? 

Итак, сегодня нам предстоит узнать, как можно запустить/остановить любой сервис в системе или вогнать в его паузу. Судя по названию рубрики, мы будем делать это программно с помощью
Delphi. 

Менеджер сервисов

Приступим. За управление сервисами в окнах отвечает менеджер сервисов (Service Control Manager, что на нашем великом и могучем означает «менеджер
управлени сервисами». Очень часто, в том числе и в документации MSDN, можно встретить сокращение
SCManager. 

Оснастка «Сервисы» управляет сервисами теми же методами, которые мы рассматриваем в этой статье.

Чтобы получить контроль над сервисами, для начала необходимо подключиться к менеджеру. Для этого используется функция OpenSCManager, которая в общем виде выглядит так:

function OpenSCManager (
lpMachineName, 
lpDatabaseName: PChar;
dwDesiredAccess: DWORD
): SC_HANDLE; stdcall;

Тут у нас всего 3 параметра: 

1. Имя компьютера, к менеджеру которого необходимо подключиться. Если есть права, то можно управлять даже удаленным компьютером. Для подключения к локальному компьютеру этот параметр можно оставить нулевым. 

2. База данных, которая нас интересует. Этот параметр должен быть равен SERVICES_ACTIVE_DATABASE или нулю. В обоих случаях результат один и тот же – выбирается активная база данных. 

3. Флаг, определяющий желаемый доступ. 

В зависимости от прав, с которыми работает пользователь, можно указать различные флаги прав доступа к менеджеру сервисов. Нас интересует полный доступ, а значит, в третьем параметре необходимо указать SC_MANAGER_ALL_ACCESS. Фулл акцесс будет возможен, только если компьютер работает под админом. Слава богам за то, что большинство ламеров работает именно под такими правами, особенно в Windows Home Edition, где каждый юзер является локальным админом. 

Если программа работает с правами LocalSystem, то можно указать следующие права доступа:

  • SC_MANAGER_CONNECT – разрешено подключение к менеджеру; 
  • SC_MANAGER_ENUMERATE_SERVICE – разрешено перечисление сервисов; 
  • SC_MANAGER_QUERY_LOCK_STATUS – разрешен запрос состояния; 
  • STANDARD_RIGHTS_READ – стандартные права чтения; 
  • SC_MANAGER_MODIFY_BOOT_CONFIG – разрешено изменение загрузки.

Сервис, который нужно тормознуть, чтобы отключить Dr. Web

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

Итак, чтобы подключиться к менеджеру управления сервисами на локальном компьютере, достаточно написать следующий код: 

var
servicemanager:Cardinal;
begin
servicemanager:=OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
end;

Рекомендую проверять результат на корректность, потому что программа может не иметь прав для подключения с запрошенными привилегиями. 

Подключение к сервису

К менеджеру мы подключились, теперь подрубимся к необходимому сервису. Для этого используется метод OpenService, который выглядит так:

function OpenService (
hSCManager: SC_HANDLE; 
lpServiceName: PChar;
dwDesiredAccess: DWORD
): SC_HANDLE; stdcall;

Как всегда, разобраться с методами поможет файл помощи

Здесь у нас опять 3 параметра: 

  1. Хэндл менеджера сервисов, который мы получили после выполнения функции
    OpenSCManager; 
  2. Имя сервиса, которым нужно управлять; 
  3. Права доступа. 

В качестве прав доступа при подключении к сервису можно указывать: 

  • SERVICE_ALL_ACCESS – полный доступ; 
  • SERVICE_START – разрешить запуск сервисов; 
  • SERVICE_STOP – разрешить останавливать сервисы; 
  • SERVICE_PAUSE_CONTINUE – разрешить вгонять сервис в паузу и возобновлять выполнение. 

Это основные права, которые тебе могут понадобиться. 

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

Управление

Ну что же, можно начинать управление. Делается это с помощью функции: 

ControlService. 
function ControlService(
hService: SC_HANDLE; 
dwControl: DWORD;
var lpServiceStatus: TserviceStatus
): BOOL; stdcall;

И снова 3 магических параметра:

  1. Хэндл сервиса, которым нужно управлять.
  2. Действие, которое нужно выполнить. Основные указываемые здесь команды — это:
    — SERVICE_CONTROL_STOP – остановить сервис;
    — SERVICE_CONTROL_PAUSE – сделать паузу, скушать «Твикс»;
    — SERVICE_CONTROL_CONTINUE – продолжить выполнение сервиса, который кушает «Твикс»;
  3. Переменная типа SERVICE_STATUS, через которую мы получим последнее состояние сервиса. 

При остановке можно встретиться с одной серьезной проблемой. Если есть зависимые работающие сервисы, то остановить требуемый сервис будет невозможно. Необходимо определить зависимости и остановить все сервисы. Но об этом чуть ниже. 

Использование менеджера

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

var
servicemanager, service:Cardinal;
ss:SERVICE_STATUS;
begin
// Открываем менеджер сервисов
servicemanager:=OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);

// Открываем сервис Messenger
service:=OpenService(servicemanager, 'Messenger', SERVICE_ALL_ACCESS);

// Проверяем на ошибочки
if service=0 then
begin
ShowMessage('Ошибка');
exit;
end;

// Останавливаем Messenger
ControlService(service, SERVICE_CONTROL_STOP, ss);

// Закрываем сервис
CloseServiceHandle(service);
end;

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

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

Ах, чуть не забыл. Все функции работы с сервисами и менеджером описаны в модуле WinSvc.pas, поэтому не забудь прописать его в разделе uses, иначе пример не скомпилируется. 

Стартуем

Обрати внимание, что при рассмотрении функции контроля ControlService я не привел флага, который отвечал бы за запуск сервиса. Нет, я не опустил его из-за ненадобности, просто за запуск отвечает совершенно другая функция —
StartService. 

function StartService(
hService: SC_HANDLE; 
dwNumServiceArgs: DWORD;
var lpServiceArgVectors: Pchar
): BOOL; stdcall;

Давай глянем на параметры этой функции.

  1. Хэндл сервиса, который нужно запустить.
  2. Количество передаваемых аргументов. Они передаются в виде строк в третьем параметре функции.
  3. Массив из строк аргументов. Каждый элемент массива – это строка, которая заканчивается нулем.

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

Со стартом могут быть проблемы. Не каждый может это сделать, особенно если для корректной работы требуется запуск других сервисов. Если результат не нулевой (true), то запуск произошел успешно, а если нулевой (false), то произошла ошибка. 

Оснастим

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

Теперь ты можешь написать собственную оснастку управления сервисами

  • QueryServiceStatus – запрашивает информацию о состоянии сервиса. У функции 2 параметра: хэндл сервиса и переменная типа SERVICE_STATUS, куда будет записан результат. 
  • CreateService – создает сервис и добавляет его в базу данных определенного менеджера управления сервисами. Параметров у этой функции много, поэтому сэкономим место. Да и инсталлировать сервисы просто и без этой функции, достаточно только запустить
    исполняемый файл. 
  • DeleteService – удаляет сервис. Параметр только один и это хэндл удаляемого сервиса. 
  • EnumDependentServices – перечисляет все сервисы, которые зависят от указанного. Таким образом можно вычислить зависимости. 
  • GetServiceDisplayName – определяет дружественное имя сервиса, которое можно увидеть в оснастке служб. 
  • EnumServicesStatus – перечисляет все установленные сервисы из базы данных и возвращает для каждого из них текущее состояние. 

Реакция

При работе с SC-менеджером нужно быть очень внимательными, потому что результат наступает не мгновенно. Если запустить пример, который ты найдешь на диске
с номером, и программно остановить сервис Messenger, то можно увидеть, что в оснастке «Сервисы» служба сообщений будет некоторое время недоступна, так как система будет останавливать сервис, обновлять базу данных и т.д. 

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

Напутствие

Для того чтобы зло-код не смог программно отрубить антивирус и внедриться в твою систему, достаточно просто работать на компьютере с правами простого пользователя, а не администратора. В этом случае код не сможет получить полного доступа к системе. Конечно, нет ничего невозможного — есть куча способов поднять права, но это весьма проблематично. 

Программное отключение сервисов лишний раз подтверждает тот факт, что защиты в окнах просто не может быть, особенно если юзер работает под правами админа. Любая зло-программа может незаметно вырубить эту защиту и уничтожить компьютер бедного пользователя. Виноват останется все тот же бедный юзер, но что он может сделать в Windows Home Edition? 

Остается только пожелать тебе удачи. Надеюсь, скоро увидимся.



Полную версию статьи, исходники и
дополнительные материалы ты можешь
найти в 12 номере Хакера за прошлый год.

Оставить мнение

Check Also

Используй, свободно! Как работает уязвимость use-after-free в почтовике Exim

В самом популярном на сегодняшний день почтовом сервере Exim был обнаружен опасный баг: ес…