..-----------------------------------------..
.. Работаем в контексте svchost.exe ..
.._________________________________________..
1. Введение
Сервисы, появившиеся в последних творениях микрософта (w2k, xp),
поставили разработку ПО на новый уровень. Написание резидентного кода
стало намного легче. Теперь не нужно знать тонкостей реализации ОС
и создавать изощренные программы, отлаживая их через жопу... Теперь все
гораздо проще. Накатал десяток строчек - и дело сделано. Скучно,
товарищи :)
На то они и микрософт, чтобы делать нашу жизнь лучше. Будь ты хоть
юзером, хоть программистом.
Информации по написанию служб (или сервисов, как угодно) в интернете
море. Спросите дядю Гугля, и он вам выдаст килограмма два ссылок.
Хорошие тексты можно найти на rsdn.ru и подобных ресурсах.
Вся инфа, которая мне попадалась - это примеры написания СВОИХ служб,
выполняющихся как отдельные процессы. Но ведь в системе присутствует
такой интересный файл, как "svchost.exe", являющийся по сути
вместилищем почти всех системных сервисов. Почему же и нам нельзя
затесаться в их число? MSDN молчит, микрософт тем более. Придется
поправить такое положение дел =)
2. О svchost.exe
Впринципе, ничего сложного в написании таких вещей нет. Вся информация
о работающих (и не работающих тоже) службах хранится в реестре по
адресу "HKLM\System\CurrentControlSet\Services". Если вы посмотрите
повнимательнее, то в значении "ImagePath" некоторых ключей будет стоять
"%SystemRoot%\system32\svchost.exe -k netsvcs", или нечто подобное.
Вот это именно то, что нам и нужно. Данная строчка говорит о том что
сервис из группы "netsvcs" нужно загрузить в контекст svchost`а. Сам же
адрес исполняемого модуля лежит в ключе "Parameters\ServiceDLL". Это и
есть одно из главных отличий служб такого типа - все они должны быть
библиотеками. И к тому же экспортировать функцию ServiceMain.
Информацию о группах загрузки svchost`а можно найти по адресу
"HKLM\Software\Microsoft\Windows NT\CurrentVersion\SvcHost". В этом
ключе есть несколько значений типа REG_MULTI_SZ, в которых перечислены
имена сервисов. Каждая группа будет загружена отдельным процессом с
именем "svchost.exe". Вот именно по этому при нажатии C-A-D, можно
наблюдать два и более файла с одинаковым именем.
Тип REG_MULTI_SZ - это некое подобие массива строк. Каждое значение в
нем завершается "\0". Концом всего массива является "\0\0". Т.е. для
"непонятливых, тупых и убогих" пример:
"hello\0mother\0fucker\0\0"
3. Пример кода
Для начала разберем код самого сервиса. Как я уже говорил, это должна
быть dll с экспортируемой функцией ServiceMain. Чтобы увидеть успешную
загрузку нашего кода в систему, он (сервис) откроет 9000 порт на машине
и при соединении вернет строку "hello\n".
Не буду приводить тут куски кода, там все очень просто. Замечу лишь,
что при заполнении структуры "SERVICE_STATUS", в поле "dwServiceType"
нужно указать значение "SERVICE_WIN32_SHARE_PROCESS". Также, если вы не
хотите, чтобы вашу службу могли завершить командой stop, можно в поле
"dwControlsAccepted" указать значение "SERVICE_ACCEPT_STOP", но при
получении такого рода сообщений ничего не делать. А можно и вообще
нифига не заполнять. Тоже должно прокатить =)
Код загрузчика рассмотрим подробнее.
При создании сервиса указываем значения "SERVICE_WIN32_SHARE_PROCESS",
"SERVICE_AUTO_START", "SERVICE_ERROR_IGNORE", т.е. говорим, что хотим
выполняться НЕ в собственном процессе, будем загружаться при старте
системы и не вести никаких логов. Имя исполняемого модуля задаем как
"%SystemRoot%\\System32\\svchost.exe -k netsvcs", т.е. будем находиться
в группе netsvcs.
В реестре по адресу "HKLM\System\CurrentControlSet\Services\ИмяСервиса"
создаем значение "Description" - описание нашей службы (так немного
легче и не нужно париться с вызовом ChangeServiceConfig2).
Далее, как я и говорил выше, в ветке "Parameters" нужно задать реальное
имя нашей dll. Что мы и делаем. Легким движением пальца по клавиатуре
создаем ее, не забывая при этом и значение внутри - "ServiceDll" с
адресом нашей библиотеки. Да, кстати. В моем примере это значение
равно "%SystemRoot%\\System32\\Services.dll" и придется ручками
скопировать файл по этому пути. В своих же исследованиях вы можете
задать любой адрес. Конечно, предварительно CopyFile() туда свой код.
И последний шаг - добавить имя созданного сервиса в группу загрузки.
Т.е. переходим по адресу "HKLM\Software\Microsoft\Windows NT\
CurrentVersion\SvcHost" и добавляем себя в ту группу, которая задана
после параметра "-k" в имени исполняемого файла. И не забудьте про
то, как формируется значение типа REG_MULTI_SZ.
И... вот впринципе и все сложные манипуляции :)
4. Тестируем
Для начала перезагрузимся. Затем посмотрим в логах, не ругалась ли
система по поводу невозможности загрузки какого-либо сервиса. Если вы
все сделали верно, то ничего подобного произойти не должно.
Убедится в том, что служба выполняется именно в контексте svchost`а
можно двумя способами:
- В командной строке написать "tasklist /svc" и поискать ее там.
- Посмотреть открытые порты на машине. Svchost.exe должен слушать 9000
порт (как мы и хотели).
5. Заключение
Странно, почему микрософт не рассказывает о том, как писать подобные
вещи... Ведь ничего сложного в этом нет. Конечно, страдает т.н.
"безопасность" системы, ведь есть большая вероятность того, что вы
своей криво написанной службой можете испоганить нежный код системных
сервисов, работающих в одном контексте с вами.
Какой в этом всем толк? Ну... главное подключить фантазию, а там уж
можно много чего придумать =)
З.Ы. Создание функции удаления такого рода сервисов идет вам в качестве
домашнего задания :) Удачного кодинга.
З.Ы2. Весь код написан на MSVC++ 6.0