Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
11
Добавлен:
27.03.2016
Размер:
116.74 Кб
Скачать

Лабораторна робота №1

Теоретичні відомості:

Тема: Використння та розробка системних служб, програмування в режимі ядра.

Завдання: Описати ієрархічну структуру компонентів режиму «ядра». Розробити програму, яка дозволяє запустити обраний сервіс, перевірити його стан, зупинити і видалити його з системи.

Служби Windows (англ. Windows Service, сервіси) - додатки, що запускаються автоматично системою при запуску Windows і виконуються незалежно від статусу користувача. Має спільні риси з концепцією демонів в Unix.

Режими роботи

У більшості випадків службам заборонено взаємодія з консоллю або робочим столом користувачів (як локальних, так і віддалених), однак для деяких сервісів можливе виключення - взаємодія з консоллю (сесією з номером 0, в якій зареєстрований користувач локально або при запуску служби mstsc з ключем / console).

Існує чотири режими для сервісів:

• заборонений до запуску;

• ручний запуск (за запитом);

• автоматичний запуск при завантаженні комп'ютера;

• обов'язковий сервіс (автоматичний запуск і неможливість (для користувача) зупинити сервіс).

Фоновий режим

Windows пропонує програму Service Control Manager, з її допомогою можна керувати створенням, видаленням, запуском і зупинкою служб. Додаток, що має статус сервісу, повинно бути написано таким чином, щоб воно могло приймати повідомлення від Service Control Manager. Потім, одним або декількома викликами API, ім'я служби та інші атрибути, такі, як його опис, реєструються в Service Control Manager.

Запуск, зупинка і зміна служб Windows

Після установки служби, її атрибути можуть бути змінені шляхом запуску «Services» з Панелі управління Windows в Administrative Tools.

Управління запуском служб при старті Windows

Список служб знаходиться в гілці реєстру HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Services. Значення параметра «Start» мають тип «REG_DWORD» і можуть приймати значення: «0», «1», «2», «3» і «4» (коли служба не запускається, тобто запуск даной служби заборонений).

Управління роботою служб з командного рядка

Управління службами можливо за допомогою командного рядка: зупинка служби - «net stop service_name», запуск служби - «net start service_name». Вилучення: sc delete "Ім'я служби" (лапки необхідні, якщо ім'я служби містить пробіли). З видаленням потрібно бути гранично обережним, так як віддалену службу повернути назад дуже і дуже важко.

 Права користувача та особливості реалізації

Сервіси Windows за замовчуванням запускаються від імені користувача «LocalSystem», який володіє повними правами в системі (переважаючими права навіть облікового запису Administrator). Робочим каталогом буде системний каталог Windows (зазвичай C: \ WINNT або C: \ WINDOWS), а каталог для зберігання тимчасових файлів буде C: \ WINNT \ TEMP.

Оскільки це не справжній користувач, а «віртуальний», з'являються деякі труднощі, коли додатку необхідно зберегти дані, пов'язані з користувачеві (user-specific data), оскільки не існує домашньої директорії цього користувача.

Важливо також те, що в разі якщо служба працює від імені локального користувача (реальний користувач створений для службових цілей) якщо пароль такого користувача змінений, сервіс не буде запускатися до тих пір, поки пароль для сервісу теж не буде змінений.

Функція OpenSCManager.

Функція OpenSCManager встановлює зв'язок з менеджером управління сервісами і відкриває його базу даних.

SC_HANDLE OpenSCManager (

  LPCTSTR lpMachineName,

  LPCTSTR lpDatabaseName,

  DWORD dwDesiredAccess

);

Параметри

lpMachineName

Покажчик на рядок (що завершується нулем), що містить ім'я комп'ютера. Якщо цей параметр дорівнює NULL або вказує на порожню рядок, то функція коннектітся до менеджера управління сервісами на локальній машині.

lpDatabaseName

Покажчик на рядок (що завершується нулем), яка містить ім'я відкривається бази даних менеджера управління сервісами. Цей параметр повинен бути рівний SERVICES_ACTIVE_DATABASE. Якщо цей параметр прирівняти NULL, то за умовчанням буде відкрита база SERVICES_ACTIVE_DATABASE.

dwDesiredAccess

Права доступу до менеджера управління сервісами. Повний список прав можна подивитися тут: Service Security and Access Rights.

Перед тим, як дозволити доступ з запитаними правами, система перевіряє права запити процесу і звіряє їх зі списком в менеджері управління сервісами.

За замовчуванням, при виклику цієї функції встановлено право SC_MANAGER_CONNECT.

Повертає значення

У разі успіху, функція повертає дескриптор бази даних менеджера управління сервісами.

У випадку помилки, функція поверне NULL. Для отримання більш детальної інформації про помилку див. функцію GetLastError.

Стандартні коди помилок, що повертаються SCM наведені в таблиці:

Значение

Описание

ERROR_ACCESS_DENIED

Доступ с указанными правами запрещён.

ERROR_DATABASE_DOES_NOT_EXIST

Указанная база данных не существует.

ERROR_INVALID_PARAMETER

Не правильный параметр.

Нотатки

Перед тим, як дозволити процесові доступ до бази даних менеджера управління сервісами з запитаними правами, система проводить перевірку безпеки.

Windows 2000 і ранні версії: Всі процеси маю такі права на доступ до бази: SC_MANAGER_CONNECT, SC_MANAGER_ENUMERATE_SERVICE, і SC_MANAGER_QUERY_LOCK_STATUS. Тим самим, якому процесу дозволяється відкрити базу менеджера управління сервісами, отримати її дескриптор і використовувати його в функціях OpenService, EnumServicesStatus, і QueryServiceLockStatus.

Windows XP: Правами SC_MANAGER_CONNECT,

C_MANAGER_ENUMERATE_SERVICE, і SC_MANAGER_QUERY_LOCK_STATUS можуть скористатися тільки авторизовані користувачі.

Використовувати функції CreateService і LockServiceDatabase можуть тільки процеси мають права Адміністратора.

Використовувати дескриптор може тільки той процес, який викликав функцію OpenSCManager. Закрити його можна за допомогою функції CloseServiceHandle.

Приклад

Див Відкриття бази даних SCManager.

Додаткова інформація

Windows NT/2000/XP: Присутній починаючи з Windows NT 3.1.

Unicode: Існує як Unicode, так і ANSI версія функції.

Тема: Оголошено в Winsvc.h; включена в Windows.h.

Бібліотека: Advapi32.lib.

Функція CreateService.

Функція CreateService створює об'єкт сервісу і додає його в базу даних менеджера управління сервісами (SCM).

SC_HANDLE CreateService(

SC_HANDLE hSCManager,

LPCTSTR lpServiceName,

LPCTSTR lpDisplayName,

DWORD dwDesiredAccess,

DWORD dwServiceType,

DWORD dwStartType,

DWORD dwErrorControl,

LPCTSTR lpBinaryPathName,

LPCTSTR lpLoadOrderGroup,

LPDWORD lpdwTagId,

LPCTSTR lpDependencies,

LPCTSTR lpServiceStartName,

LPCTSTR lpPassword

);

Параметри

hSCManager

Дескриптор бази даних менеджера управління сервісами (SCM). Цей дескриптор можна отримати за допомогою функції OpenSCManager з правом доступу SC_MANAGER_CREATE_SERVICE. Більш докладно див Безпека сервісів і права доступу.

lpServiceName

Покажчик на рядок (що завершується нулем), що містить ім'я створюваного сервісу. Максимальна довжина рядка не повинна перевищувати 256 символів. В імені сервісу можна використовувати символи "/" і "\".

lpDisplayName

Покажчик на рядок (що завершується нулем), що містить ім'я, яке буде відображатися в користувальницьких додатках. Максимальна довжина рядка не повинна перевищувати 256 символів.

dwDesiredAccess

Тип доступу до сервісу. Перед тим, як дозволити запитуваний доступ, система перевірить привелегии викликав процесу. Список значень див. Безпека сервісів і права доступу.

dwServiceType

Тип сервісу. Цей параметр може містити одне з наступних значень:

Тип

Описание

SERVICE_FILE_SYSTEM_DRIVER

Сервис драйвера файловой системы.

SERVICE_KERNEL_DRIVER

Сервис драйвера.

SERVICE_WIN32_OWN_PROCESS

Сервис, который запускается в собственном процессе.

SERVICE_WIN32_SHARE_PROCESS

Сервис, который делает доступным процесс для других сервисов.

Если указать SERVICE_WIN32_OWN_PROCESS или SERVICE_WIN32_SHARE_PROCESS, и если при этом сервис запускается с правами системы, то Вы можете так же указать следующий тип:

Тип

Описание

SERVICE_INTERACTIVE_PROCESS

Сервис может взаимодействовать с рабочим столом.

См. Интерактивные сервисы.

dwStartType

Тип запуска сервиса. Этот параметр может иметь одно из следующих значений:

Тип

Описание

SERVICE_AUTO_START

Сервис запускается автоматически менеджером управления сервисами при старте системы.

SERVICE_BOOT_START

Драйвер устройства стартует при загрузке системы. Это значение доступно только для сервисов драйверов.

SERVICE_DEMAND_START

Сервис запускается из менеджера управления сервисами, когда процесс вызывает функцию StartService.

SERVICE_DISABLED

Сервис не должен запускаться. Попытка запуска такого сервиса приведёт к коду ошибки ERROR_SERVICE_DISABLED.

SERVICE_SYSTEM_START

Драйвер устройства запускается функцией IoInitSystem. Это значение доступно только для сервисов драйверов.

dwErrorControl

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

Значение

Описание

SERVICE_ERROR_IGNORE

Запускающая программа записывает ошибку в лог, но продолжает операцию запуска.

SERVICE_ERROR_NORMAL

Запускающая программа записывает ошибку в лог и выводит диалоговое окошко с сообщением об ошибке, но продолжает операцию запуска.

SERVICE_ERROR_SEVERE

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

SERVICE_ERROR_CRITICAL

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

lpBinaryPathName

Покажчик на рядок (закінчується нулем), яка містить повний шлях до виконуваного файлу сервісу. Якщо шлях містить пробіли, то він повинен бути укладений у лапки. Наприклад, "d: \ \ my share \ \ myservice.exe" необхідно вказати як

"\" D: \ \ my share \ \ myservice.exe \ "".

Шлях так само може містити аргументи для автоматично-запускається сервісу. Наприклад, "d: \ \ myshare \ \ myservice.exe arg1 arg2". Ці параметри передаються в точку входу сервісу (зазвичай у функцію main).

lpLoadOrderGroup

Покажчик на рядок (закінчується нулем), яка містить ім'я групи, членом якої є сервіс. Якщо сервіс не є членом групи, то можна вказати NULL або порожній рядок.

Запускає програма використовує порядок завантаження груп, для завантаження груп сервісів в зазначеному порядку щодо інших груп. Список груп міститься в значенні ServiceGroupOrder, яке знаходиться в наступному ключі реєстру:

HKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Control

lpdwTagId

Покажчик на змінну, в яку буде записаний унікальне значення тега, яке ідентифікує групу, зазначену в параметрі lpLoadOrderGroup. Якщо Ви не збираєтеся міняти існуючий тег, то вкажіть в цьому параметрі NULL.

Цей тег можна використовувати для вказівки порядку завантаження сервісів в групі, указавши вектор у значенні GroupOrderList ключа реєстру:

HKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Control

Теги доступні тільки для сервісів драйверів, які мають типи запуску SERVICE_BOOT_START або SERVICE_SYSTEM_START.

lpDependencies

Покажчик на масив (завершується двома нулями) імен (розділених нулями) сервісів або груп сервісів, які система повинна запустити до запуску цього сервісу. Якщо сервіс не залежить від інших сервісів, то в цьому параметрі потрібно вказати NULL або порожній рядок. Залежність від групи означає, що цей сервіс може бути запущений тільки тоді, коли як мінімум один з сервісів групи вдалося запустити після спроби старту всіх членів групи.

Для групи необхідно використовувати префікс SC_GROUP_IDENTIFIER, щоб відрізнити від імені сервіс, так як сервіси та групи сервісів використовують одне і теж простір імен.

lpServiceStartName

Покажчик на рядок (що завершується нулем), яка містить ім'я аккаунта, з правами якого буде запущено сервіс. Якщо тип сервісу SERVICE_WIN32_OWN_PROCESS, то використовувати ім'я аккаунта необхідно у вигляді DomainName \ UserName. Процес сервісу буде Авторизованих в системі як цей користувач. Якщо акаунт присутня в поточному домені, то можна просто вказати. \ UserName.

Якщо цей параметр задати як NULL, то CreateService буде використовувати Системний аккаунт. Якщо тип сервісу вказати як SERVICE_INTERACTIVE_PROCESS, то сервіс повинен бути запущений з правами системи.

Windows XP: Якщо вказати в цьому параметрі NT AUTHORITY \ LocalService, то CreateService використовує системний аккаунт. Якщо ж цей параметр задати як NT AUTHORITY \ NetworkService, то CreateService буде використовувати аккаунт NetworkService.

Windows NT 4.0 і вище: Якщо тип сервісу SERVICE_WIN32_SHARE_PROCESS, ти необхідно запускати сервіс з правами системи. У Windows 2000 і пізніше, можна запускати процес, доступний іншим сервісам під будь-яким користувачем.

Якщо тип сервісу SERVICE_KERNEL_DRIVER або SERVICE_FILE_SYSTEM_DRIVER, то цей параметр повинен містити ім'я об'єкта драйвера, яке система використовує для завантаження драйвера пристрою, або вказати NULL, якщо драйвер використовує ім'я об'єкта драйвера створене підсистемою вводу / виводу (I / O).

lpPassword

Покажчик на рядок (закінчується нулем), яка містить пароль до акаунту, зазначеної в параметрі lpServiceStartName. Якщо аккаунт не має пароля або якщо сервіс запускається з правами LocalService, NetworkService, або системи, то можна вказати на порожню рядок. Більш докладно див Service Record List.

Для сервісів драйверів пароль ігнорується.

Повертає значення

У разі успіху, функція поверне дескриптор сервісу.

У випадку помилки, функція поверне NULL. Для отримання більш детальної інформації про помилку, можна скористатися функцією GetLastError.

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

Значение

Описание

ERROR_ACCESS_DENIED

Менеджер управления сервисами не дал разрешения на выполнение операции SC_MANAGER_CREATE_SERVICE.

ERROR_CIRCULAR_DEPENDENCY

Указана зацикленная зависимость.

ERROR_DUPLICATE_SERVICE_NAME

Отображаемое имя уже присутствует в базе менеджера управления сервисами как имя сервиса либо как другое отображаемое имя.

ERROR_INVALID_HANDLE

Не правильный дескриптор менеджера управления сервисами.

ERROR_INVALID_NAME

Не правильное имя сервиса.

ERROR_INVALID_PARAMETER

Неправильно указан параметр.

ERROR_INVALID_SERVICE_ACCOUNT

Аккаунт, указанный в параметре lpServiceStartName не существует.

ERROR_SERVICE_EXISTS

Указанный сервис уже существует в базе данных.

зауваження

Функція CreateService створює об'єкт сервісу і прописує його в базі менеджера управління сервісами створивши в реєстрі ключ з таким же ім'ям що і ім'я сервісу в наступному ключі:

HKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Services

У цьому ключі записуються значення, вказані у функціях CreateService, ChangeServiceConfig, і ChangeServiceConfig2. Ці значення перераховані в наступній таблиці:

Значение

Описание

DependOnGroup

Группы, указанные в lpDependencies, от которых зависит сервис.

DependOnService

Другие сервисы, указанные в lpDependencies, от которых зависит указанный сервис.

Description

Описание, указанное в ChangeServiceConfig2.

DisplayName

Отображаемое имя, указанное в lpDisplayName.

ErrorControl

Уровень контроля ошибок, указанный в dwErrorControl.

FailureActions

Действия в случае ошибки, указанные в ChangeServiceConfig2.

Group

Порядок загрузки групп, указанный в lpLoadOrderGroup.

ImagePath

Имя исполняемого файла, указанного в lpBinaryPathName.

ObjectName

Имя аккаунта, указанного в lpServiceStartName.

Start

Как запускаться сервису. Указано в dwStartType.

Tag

Тэг идентификации, указанный в lpdwTagId.

Type

Тип сервиса, указанный в dwServiceType.

Програми установки і сам сервіс можуть створювати додаткові ключі для додаткової інформації про сервіс.

Отриманий дескриптор буде доступним тільки для того процесу, який викликав CreateService. Закрити його можна за допомогою функції CloseServiceHandle.

Якщо Ви створюєте процес, доступний іншим процесам, то уникайте виклику таких функцій як ExitProcess. А так само не вивантажуйте DLL сервісу.

Запуск сервісу.

Нижче представлений приклад, який для запуску сервісу відкриває дескриптор сервісу з бази сервісів, а потім передає його в функцію StartService. Після запуску сервісу, приклад використовує структуру SERVICE_STATUS, повертану функцією QueryServiceStatus, щоб отримати стан сервісу.

 

DWORD StartSampleService ()

{

    SERVICE_STATUS ssStatus;

    DWORD dwOldCheckPoint;

    DWORD dwStartTickCount;

    DWORD dwWaitTime;

    DWORD dwStatus;

    schService = OpenService (

        schSCManager, / / ​​база сервісів SCM

        "Sample_Srv", / / ​​ім'я сервісу

        SERVICE_ALL_ACCESS);

    if (schService == NULL)

    {

        MyErrorExit ("OpenService");

    }

    if (! StartService (

            schService, / / ​​дескриптор сервісу

            0, / / ​​кількість аргументів

            NULL)) / / ні аргументів

    {

        MyErrorExit ("StartService");

    }

    else

    {

        printf ("Service start pending. \ n");

    }

    / / Перевіряємо стан сервісу до тих пір, поки він не запуститься.

    if (! QueryServiceStatus (

            schService, / / ​​дескриптор сервісу

            & SsStatus)) / / адресу структури з інформацією про сервіс

    {

        MyErrorExit ("QueryServiceStatus");

    }

    / / Зберігаємо лічильник тиків і початкову точку.

    dwStartTickCount = GetTickCount ();

    dwOldCheckPoint = ssStatus.dwCheckPoint;

    while (ssStatus.dwCurrentState == SERVICE_START_PENDING)

    {

        / / Не потрібно чекати довше, ніж приблизний час,

        / / Необхідне для старту. Зазвичай очікувати краще всього одну

        / / Десятий цього значення, але не більше одне секунди

        / / І ніяк не більше 10 секунд.

        dwWaitTime = ssStatus.dwWaitHint / 10;

        if (dwWaitTime <1000)

            dwWaitTime = 1000;

        else if (dwWaitTime> 10000)

            dwWaitTime = 10000;

        Sleep (dwWaitTime);

        / / Знову перевіряємо статус.

        if (! QueryServiceStatus (

                schService, / / ​​дескриптор сервісу

                & SsStatus)) / / адресу структури

            break;

        if (ssStatus.dwCheckPoint> dwOldCheckPoint)

        {

            / / Сервіс в процесу старту.

            dwStartTickCount = GetTickCount ():

            dwOldCheckPoint = ssStatus.dwCheckPoint;

        }

        else

        {

            if (GetTickCount ()-dwStartTickCount> ssStatus.dwWaitHint)

            {

                / / Час до старту не змінилося

                break;

            }

        }

    }

    if (ssStatus.dwCurrentState == SERVICE_RUNNING)

    {

        printf ("StartService SUCCESS. \ n");

        dwStatus = NO_ERROR;

    }

    else

    {

        printf ("\ nСервіс на запущений. \ n");

        printf ("Current State:% d \ n", ssStatus.dwCurrentState);

        printf ("Exit Code:% d \ n", ssStatus.dwWin32ExitCode);

        printf ("Service Specific Exit Code:% d \ n",

            ssStatus.dwServiceSpecificExitCode);

        printf ("Check Point:% d \ n", ssStatus.dwCheckPoint);

        printf ("Wait Hint:% d \ n", ssStatus.dwWaitHint);

        dwStatus = GetLastError ();

    }

    CloseServiceHandle (schService);

    return dwStatus;

}

Соседние файлы в папке Semestr2