..-----------------------------------------..
..    Работаем в контексте 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