Страница:
wwwsysinternals.com
).
C другой стороны, было бы интересно выяснить, что импортируют DLL-модули подсистемы Windows (скажем, Kernel32.dll или Adva-pi32.dll) и какие функции они вызывают в Ntdll.
Также представляет интерес содержимое Ntoskrnl.exe: хотя в Windows DDK документированы многие экспортируемые подпрограммы, используемые драйверами режима ядра, немалая их часть не описана. Возможно, вас заинтересует содержимое таблицы импорта для Ntoskrnl и HAL, где перечислены функции HAL, используемые Ntoskrnl, и наоборот.
B таблице 2-7 приведено большинство общеупотребительных префиксов имен функций в компонентах исполнительной системы. B каждом из таких компонентов также используются слегка модифицированные префиксы, обозначающие внутренние функции: либо за первой буквой префикса указывается / (от internal),либо префикс заканчивается на букву p(от private).Так, Kiотносится к внутренним функциям ядра, a Psp- к внутренним функциям поддержки процессов.
Понимая схему именования системных процедур Windows, расшифровывать имена экспортируемых функций гораздо легче. Общий формат выглядит так:
‹префикс›‹операция›‹объект›
где префикс -внутренний компонент, экспортирующий процедуру, операция- название операции, выполняемой над объектом или ресурсом, а объект- объект, над которым проводится эта операция.
Например, ExAllocatePoolWithTagявляется процедурой поддержки исполнительной системы, которая выделяет память из пула подкачиваемых или неподкачиваемых страниц. KeInitializeThreadпредставляет собой процедуру для создания и инициализации объекта ядра «поток».
B каждой системе Windows выполняются перечисленные ниже процессы. (Два из них, IdIe и System, не являются процессами в строгом смысле этого слова, поскольку они не выполняют какой-либо код пользовательского режима.)
(o)Процесс IdIe (включает по одному потоку на процессор для учета времени простоя процессора).
(o)Процесс System (содержит большинство системных потоков режима ядра).
(o)Диспетчер сеансов (Smss.exe).
(o)Подсистема Windows (Csrss.exe).
(o)Процесс входа в систему (Winlogon.exe).
(o)Диспетчер управления сервисами (Services.exe) и создаваемые им дочерние процессы сервисов (например, универсальный процесс для хостинга сервисов, Svchost.exe).
(o)Серверный процесс локальной аутентификации (Lsass.exe).
Чтобы понять взаимоотношения этих процессов, полезно просмотреть «дерево» процессов, отражающее связи между родительскими и дочерними процессами. Увидев, кем создается тот или иной процесс, вам будет легче понять, откуда берется каждый процесс. Ha рис. 2-6 показана часть экранного снимка дерева процессов с комментариями по нескольким первым процессам. (Process Explorer позволяет добавлять комментарии для индивидуальных процессов и выводить их как дополнительную колонку в окне.)
B следующих разделах поясняются основные системные процессы, перечисленные на рис. 2-6. Хотя в этих разделах дается краткое описание последовательности запуска данных процессов, подробно все этапы загрузки Windows рассматриваются в главе 5.
Первый процесс, показанный на рис. 2-6, является процессом простоя системы (system idle process). Как будет показано в главе 6, процессы идентифицируются по именам их образов. Однако этот процесс (как и процесс System) не выполняет реальный код пользовательского режима (в том смысле, что в каталоге \Windows нет «System IdIe Process.exe»). Кроме того, разные утилиты из-за особенностей реализации по-разному именуют его. B таблице 2-8 приводится несколько имен процесса IdIe (с идентификатором 0); подробнее о нем рассказывается в главе 6.
A теперь рассмотрим системные потоки и предназначение каждого системного процесса, выполняющего реальный код.
Две строки, помеченные как Interrupts и DPCs, отражают время, затраченное на обслуживание прерываний и обработку отложенных вызовов процедур (deferred procedure calls, DPC). Эти механизмы объясняются в главе 3. Заметьте: хотя Process Explorer показывает эти строки в списке процессов, они не имеют отношения к процессам. Они выводятся потому, что ведут учет процессорного времени, не выделенного какому-либо процессу. Ho Task Manager (Диспетчер задач) рассматривает время, затраченное на обработку преры-
ваний и DPC, как время простоя системы. Поэтому система, занятая интенсивной обработкой прерываний, будет выглядеть в Task Manager так, будто она ничем не занимается.
Процесс System (с идентификатором 8 в Windows 2000 и идентификатором 4 в Windows XP и Windows Server 2003) служит носителем особых потоков, работающих только в режиме ядра, - системных потоков режима ядра(kernel-mode system threads). У системных потоков имеются все атрибуты и контексты обычных потоков пользовательского режима (например, контекст оборудования, приоритет и т. д.), но они отличаются тем, что выполняются только в режиме ядра внутри системного кода, загруженного в системное пространство, - будь то Ntoskrnl.exe или какой-либо драйвер устройства. Кроме того, у системных потоков нет адресного пространства пользовательского процесса, и поэтому нужная им динамическая память выделяется из куч памяти операционной системы, например из пула подкачиваемых или неподкачиваемых страниц.
Системные потоки создаются функцией PsCreateSystemThread(документирована в DDK), вызываемой только в режиме ядра. Windows, как и драйверы устройств, создает системные потоки при инициализации системы для выполнения действий, требующих получения контекста потока, например для выдачи и ожидания запросов на ввод-вывод или опроса устройства. Скажем, диспетчер памяти использует системные потоки для реализации таких функций, как запись измененных страниц в страничный файл (page file) или в спроецированные файлы, загрузки процессов в память или выгрузки из нее и т. д. Ядро создает системный поток под названием «диспетчер настройки баланса» (balance set manager), активизируемый раз в секунду для инициации при необходимости различных событий, связанных с планированием и управлением памятью. Диспетчер кэша также использует системные потоки для реализации как опережающего чтения, так и отложенной записи. Драйвер файл-сервера (Srv.sys) с помощью системных потоков отвечает на сетевые запросы ввода-вывода применительно к файлам на общих дисковых разделах, доступных в сети. Даже драйвер дисковода гибких дисков создает свой системный поток для опроса этого устройства (это повышает эффективность опроса, потому что драйвер дисковода гибких дисков, управляемый прерываниями, расходует много системных ресурсов). Подробнее о конкретных системных потоках см. главы, где рассматриваются соответствующие компоненты.
По умолчанию владельцем системных потоков является процесс System, но драйверы могут создавать системные потоки в любом процессе. Например, драйвер подсистемы Windows (Win32k.sys) создает системные потоки в процессе подсистемы Windows (Csrss.exe), чтобы облегчить доступ к данным в адресном пространстве этого процесса в пользовательском режиме.
Если вы занимаетесь поиском причин неполадок или системным анализом, полезно сопоставить выполнение индивидуальных системных потоков с создавшими их драйверами или даже с подпрограммой, содержащей соответствующий код. Так, на сильно загруженном файл-сервере процесс System скорее всего потребляет значительную часть процессорного времени. Ho для определения того, какой именно драйвер или компонент операционной системы выполняется, просто знать, что процесс System в данный момент выполняет «какой-то системный поток», недостаточно.
Так что, если в процессе System выполняются потоки, сначала определите, какие это потоки (например, с помощью оснастки Performance). Найдя такой поток (или потоки), посмотрите, в каком драйвере началось выполнение системного потока (это по крайней мере укажет на наиболее вероятного создателя потока), либо проанализируйте стек вызовов (или хотя бы текущий адрес) интересующего вас потока, что позволит определить, в каком месте он сейчас выполняется.
Оба этих метода демонстрируются следующими экспериментами.
ЭКСПЕРИМЕНТ: идентификация системных потоков в процессе System
Вы можете убедиться, что потоки внутри процесса System должны быть потоками режима ядра, поскольку стартовый адрес каждого из них больше адреса начала системного пространства (которое по умолчанию начинается с 0x80000000, если система загружена без параметра /3GB в Boot.ini). Кроме того, обратив внимание на процессорное время, выделяемое этим потокам, вы увидите, что они занимают процессорное время только при выполнении в режиме ядра. Чтобы определить драйвер, создавший системный поток, найдите стартовый адрес потока (с помощью Pviewer.exe) и ищите драйвер с базовым адресом, ближайшим (с меньшей стороны) к этому стартовому адресу. Утилита Pstat в конце своих выходных данных, как и команда !driversотладчика ядра, сообщает базовые адреса каждого загруженного драйвера устройства.
Чтобы быстро найти текущий адрес потока, воспользуйтесь командой !stacks 0отладчика ядра. Ниже приводится образец вывода, полученный на работающей системе с помощью LiveKd.
B первом столбце выводятся идентификаторы процесса и потока (в виде «Идентификатор процесса. Идентификатор потока»). Bo втором сообщается текущий адрес потока, в третьем - состояние потока: ожидает, готов или выполняется (о состояниях потоков см. главу 6). B последнем столбце показывается адрес вершины стека потока. Эта информация помогает определить драйвер, в котором началось выполнение того или иного потока. Имя функции потока в Ntoskrnl дает дополнительную подсказку о том, что именно делает поток.
Однако, если выполняемый поток является одним из рабочих потоков системы (ExpWorkerThread), вы не сможете точно сказать, что он делает, поскольку любой драйвер может давать задания рабочему потоку системы. B этом случае единственный выход - поставить точку прерывания в ExQueueWorkItem.По достижении этой точки введите !dso work_queue_item esp+4 .Эта команда даст вам первый аргумент функции ExQueueWorkItem,представляющий собой указатель на структуру рабочего элемента, которая в свою очередь содержит адрес процедуры рабочего потока, вызываемой в его контексте. B качестве альтернативы можно использовать команду kотладчика ядра, которая сообщает текущее содержимое стека вызовов. A это подскажет, какой драйвер отправил задание рабочему потоку.
ЭКСПЕРИМЕНТ: увязка системного потока с драйвером устройства
B этом эксперименте мы посмотрим, как увязать активность процессора в процессе System с системным потоком (и драйвером, к которому он относится), вызывающим эту активность. Это важно: чтобы по-настоящему понять, что происходит, нужно перейти на уровень потоков процесса System. B данном случае мы вызовем активность системного потока, создав нагрузку файлового сервера на компьютере. (Драйвер файл-сервера Srv.sys создает системные потоки для обработки входящих запросов на файловый ввод-вывод. Подробнее об этом компоненте см. главу 13.)
1. Откройте окно командной строки.
2. Создайте список всех каталогов на диске С, используя сетевой путь для доступа к этому диску. Например, если имя вашего компьютера - COMPUTERl, введите dir \\computerl\c$ /s.(Ключ /sзаставляет перечислять все подкаталоги.)
3. Запустите Process Explorer и дважды щелкните процесс System.
4. Откройте вкладку Threads.
5. Отсортируйте список по столбцу CSwitch Delta (разница по числу переключений контекста). Вы должны увидеть один или более потоков в Srv.sys, как показано на следующей иллюстрации.
Если вы видите работающий системный поток и не уверены, какой это драйвер, нажмите кнопку Module, которая открывает окно свойств для файла. Например, нажатие кнопки Module при выбранном, как на предыдущей иллюстрации, потоке в Srv.sys выводит результаты в следующем окне.
Диспетчер сеансов (Session Manager) ( \Windows\System32\Smss.exe) является первым процессом пользовательского режима, создаваемым в системе. Он порождается системным потоком режима ядра, отвечающим за последний этап инициализации исполнительной системы и ядра.
Диспетчер сеансов отвечает за некоторые важные этапы запуска Windows, такие как создание дополнительных страничных файлов, выполнение отложенных операций по копированию, переименованию и удалению файлов, а также создание системных переменных окружения. Он также запускает процессы подсистем (обычно только Csrss.exe) и Winlogon, который в свою очередь создает остальные системные процессы.
Значительная часть сведений о конфигурации, хранящихся в реестре и используемых при инициализации Smss, находится в HKLM\SYSTEM\Current-ControlSet\Control\Session Manager. Некоторые из этих данных поясняются в главе 5 в разделе по Smss. (Более подробное описание разделов и параметров см. в справочном файле Regentry.chm из ресурсов Windows 2000).
После выполнения этих этапов инициализации главный поток Smss переходит к бесконечному ожиданию описателей процессов Csrss и Winlogon. Так как от них зависит функционирование Windows, при неожиданном завершении любого из них Smss вызывает крах системы (с кодом STATUSSYSTEM_ PROCESS_TERMINATED, или 0xC000021A). Smss также ожидает запросы на загрузку, события отладки и запросы на запуск новых сеансов сервера терминала. (Описание служб терминала см. в главе 1.)
Сеанс Terminal Services создается Smss. Когда Smss получает запрос на создание сеанса, он сначала вызывает NtSetSystemInformationс запросом на настройку сеансовых структур данных режима ядра. Это приводит к вызову внутренней функции диспетчера памяти MmSessionCreate,настраивающей виртуальное адресное пространство сеанса, которое будет содержать пул подкачиваемой памяти для сеанса и сеансовые структуры данных, создаваемые подсистемой Windows (а точнее, ее частью, работающей в режиме ядра), а также другими драйверами устройств. (Детали см. в главе 7). Затем Smss создает экземпляр Winlogon и Csrss для данного сеанса.
Процесс входа BWindows ( \Windows\System32\Winlogon.exe) обрабатывает интерактивный вход пользователя в систему и выход из нее. При нажатии комбинации клавиш SAS (secure attention sequence) Winlogon получает уведомление о запросе пользователя на вход в систему. По умолчанию SAS в Windows представляет собой комбинацию клавиш Ctrl+Alt+Del. Назначение SAS - защита пользователя от программ перехвата паролей, имитирующих процесс входа в систему, так как эту комбинацию клавиш нельзя перехватить в приложении пользовательского режима.
Идентификация и аутентификация при входе в систему реализованы в заменяемой DLL под названием GINA (Graphical Identification and Authentication). Стандартная GINA Windows, Msgina.dll, реализует интерфейс для входа в систему по умолчанию. Однако разработчики могут включать свои GINA DLL, реализующие другие механизмы аутентификации и идентификации вместо стандартного метода Windows на основе проверки имени и пароля пользователя - например, на основе распознавания образцов голоса. Кроме того, Winlogon может загружать дополнительные DLL компонентов сетевого доступа для дальнейшей аутентификации. Эта функция позволяет нескольким компонентам доступа к сетям единовременно собирать все необходимые регистрационные данные в процессе обычного входа в систему.
После ввода имя и пароль пользователя посылаются для проверки серверному процессу локальной аутентификации (local security authentication server process, LSASS) ( \Windows\System32\Lsass.exe, описываемому в главе 8). LSASS вызывает соответствующую функциональность (реализованную в виде DLL) для проверки соответствия введенного пароля с тем, что хранится в активном каталоге или SAM (части реестра, содержащей определения пользователей и групп).
После успешной аутентификации LSASS вызывает какую-либо функцию в мониторе состояния защиты (например , NtCreateToken),чтобы сгенерировать объект «маркер доступа» (access token object), содержащий профиль безопасности пользователя. Впоследствии Winlogon использует его для создания начального процесса оболочки. Информация о начальном процессе (или процессах) хранится в параметре Userinit в разделе реестра HKLM\ SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon. (По умолчанию начальным процессом считается Userinit.exe, но в списке может быть более одного образа.)
Userinit выполняет некоторые действия по инициализации пользовательской среды (например, запускает сценарии регистрации и активизирует групповые политики), а затем ищет в реестре параметр Shell (в указанном выше разделе Winlogon) и создает процесс для запуска определенной системной оболочки (по умолчанию - Explorer.exe). После этого процесс Userinit завершается. Вот почему для Explorer.exe не показывается родительский процесс - он уже завершился. Иначе говоря, Explorer является «внучатым» процессом Winlogon. (Имена процессов, чьи родительские процессы уже завершены, в списке Tlist выравниваются по левому краю.)
Winlogon активен не только при входе и выходе пользователя, но и при перехвате ввода SAS с клавиатуры. Например, когда вы нажимаете Ctrl+Alt+ DeI после входа в систему, Winlogon открывает диалоговое окно Windows Security (Безопасность Windows), предлагающее на выбор выход из системы, запуск Task Manager, блокировку рабочей станции, завершение работы системы и т. д.
Полное описание этапов процесса входа см. в разделе «Smss, Csrss и Winlogon» главы 5. Подробнее об аутентификации см. главу 8. Подробнее о вызываемых функциях интерфейса LSASS (чьи имена начинаются с Lsd)см. документацию Platform SDK.
Вспомните, что термин «сервисы» в Windows обозначает как серверные процессы, так и драйверы устройств. B этом разделе обсуждаются сервисы, являющиеся процессами пользовательского режима. Они похожи на демоны UNIX или обособленные процессы VMS в том смысле, что могут быть сконфигурированы на автоматический запуск при загрузке системы, не требуя интерактивного входа. Их также можно запустить вручную, например, с помощью оснастки Services (Службы) или вызовом Windows-функции StartSer-vice.Как правило, сервисы не взаимодействуют с вошедшим в систему пользователем, хотя при особых условиях это возможно (см. главу 4).
Этими сервисами управляет специальный системный процесс, диспетчер управления сервисами (service control manager) (\Windows\System32\Servi-ces.exe), отвечающий за запуск, остановку процессов сервисов и взаимодействие с ними. Сервисы представляют собой просто Windows-образы исполняемых программ, вызывающие особые Windows-функции для взаимодействия с диспетчером управления сервисами и с его помощью выполняющие такие операции, как регистрация успешного запуска сервиса, ответы на запросы о состоянии, приостановку или завершение работы сервиса. Сервисы определяются в разделе реестра HKLM\SYSTEM\CurrentControlSet\Services. Сведения о подразделах и параметрах, относящихся к сервисам, см. в справочном файле Regentry.chm в ресурсах Windows.
Учтите, что у сервисов есть три имени: имя процесса, выполняемого в системе, внутреннее имя в реестре и так называемое отображаемое имя (display name), которое можно увидеть в оснастке Services (Службы). (He у каждого сервиса есть отображаемое имя, и в случае его отсутствия используется внутреннее имя.) Сервисы Windows также содержат поле описания, где находится более подробная информация о том, что делает конкретный сервис.
Чтобы выяснить, какие именно сервисы содержатся в том или ином процессе, введите команду tlist /s.Ho заметьте, что иногда один процесс совместно используется несколькими сервисами. Код типа в реестре позволяет узнать, какие сервисы имеют собственные процессы и какие из них делят процессы с другими сервисами данного образа файла.
B виде сервисов реализуются некоторые компоненты Windows, например диспетчер очереди печати (спулер), журнал системных событий, планировщик задач, а также ряд сетевых компонентов.
ЭКСПЕРИМЕНТ: вывод списка установленных сервисов
Чтобы вывести список установленных сервисов (служб), дважды щелкните значок Administrative Tools (Администрирование) в окне Control Panel (Панель управления) и выберите Services (Службы). Вы должны увидеть что-нибудь в таком роде:
Для просмотра детальных сведений о сервисе щелкните правой кнопкой мыши имя сервиса и выберите команду Properties (Свойства). Ниже показан пример окна свойств для службы Print Spooler (Диспетчер очереди печати).
Обратите внимание, что поле Path To Executable (Исполняемый файл) указывает на программу, включающую данный сервис. Помните, что некоторые сервисы разделяют процессы с другими сервисами, поэтому число сервисов и используемых ими процессов не всегда находится в соотношении «один к одному».
ЭКСПЕРИМЕНТ: просмотр сервисов внутри сервисных процессов
Process Explorer выделяет процессы, которые являются хостами одного и более сервисов. (Для настройки поведения Process Explorer выберите Configure Highlighting в меню Options.) Дважды щелкнув процесс - хост сервисов, вы откроете вкладку Services, где перечисляются сервисы внутри этого процесса. При этом по каждому сервису выводится имя раздела реестра, где определен данный сервис, отображаемое имя, видимое администратору, и текст описания для этого сервиса (если такой текст есть). Например, в Windows XP список сервисов в процессе Svchost.exe, выполняемом под учетной записью System, выглядит следующим образом.
Подробнее о сервисах рассказывается в главе 4.
B этой главе мы познакомились с общими аспектами системной архитектуры Windows. Мы также рассмотрели ключевые компоненты Windows и принципы их взаимодействия. B следующей главе будет подробнее рассказано о базовых системных механизмах, на которые опираются эти компоненты, в том числе о синхронизации и диспетчере объектов.
B Microsoft Windows существует несколько базовых механизмов, которыми пользуются компоненты режима ядра: исполнительная система (executive), ядро и драйверы устройств. B этой главе описываются следующие системные механизмы (а также способы их использования):
(o)диспетчеризация ловушек (trap dispatching), в том числе прерываний, DPC (deferred procedure call), APC (asynchronous procedure call), исключений и системных сервисов;
(o)диспетчер объектов исполнительной системы;
(o)синхронизация, в том числе спин-блокировки, объекты диспетчера ядра (kernel dispatcher objects) и реализация механизмов ожидания;
(o)системные рабочие потоки;
(o)различные механизмы вроде поддержки глобальных флагов Windows;
(o)LPC (local procedure call);
(o)Kernel Event Tracing;
(o)Wow64.
Прерывания и исключения - такие ситуации в операционной системе, в которых нормальный поток выполнения кода процессором прерывается. Эти ситуации обнаруживаются как программным, так и аппаратным обеспечением. Термин ловушка(trap) относится к механизму, благодаря которому при прерывании или исключении процессор перехватывает контроль над выполняемым потоком и передает управление определенной части операционной системы. B Windows процессор передает управление обработчику ловушек(trap handler) - функции, специфичной для конкретного прерывания или исключения. Рис. 3-1 иллюстрирует некоторые ситуации, в которых активизируются обработчики ловушек.
Ядро различает прерывания и исключения: прерывание(interrupt) является асинхронным событием (т. е. оно может произойти в любой момент независимо от текущих команд, выполняемых процессором). Прерывания в основном генерируются устройствами ввода-вывода и таймерами. Их можно включать и отключать. Исключение(exception), напротив, представляет собой синхронное событие, являющееся результатом выполнения конкретной команды. Повторный запуск программы в аналогичных условиях с теми же данными позволит воспроизвести исключение. Примерами исключений могут служить нарушения доступа (ошибки защиты памяти), выполнение некоторых команд отладчика, а также попытки деления на нуль. Ядро также считает исключениями вызовы системных сервисов (хотя с точки зрения технической реализации это системные ловушки).
Прерывания и исключения можно генерировать как программно, так и аппаратно. Например, исключение «bus error» (ошибка шины) возникает из-за аппаратной ошибки, а причиной исключения «divide-by-zero» (деление на нуль) является ошибка в программе. Аналогичным образом прерывания могут генерироваться устройствами ввода-вывода или самим ядром (такие программные прерывания, как, например, APC или DPC).
При аппаратном прерывании или исключении процессор записывает статусную информацию в стек ядра для прерванного потока, чтобы впоследствии можно было вернуться к исходной точке в потоке управления и продолжить выполнение команд так, будто ничего не произошло. Если поток выполнялся в пользовательском режиме, Windows переключается на стек режима ядра для потока. Затем создает в стеке ядра прерванного потока фрейм ловушки(trap frame), в котором сохраняет информацию о состоянии потока. Фрейм ловушки является подмножеством полного контекста потока (см. главу 6), и вы можете просмотреть его определение, введя в отладчике ядра команду
C другой стороны, было бы интересно выяснить, что импортируют DLL-модули подсистемы Windows (скажем, Kernel32.dll или Adva-pi32.dll) и какие функции они вызывают в Ntdll.
Также представляет интерес содержимое Ntoskrnl.exe: хотя в Windows DDK документированы многие экспортируемые подпрограммы, используемые драйверами режима ядра, немалая их часть не описана. Возможно, вас заинтересует содержимое таблицы импорта для Ntoskrnl и HAL, где перечислены функции HAL, используемые Ntoskrnl, и наоборот.
B таблице 2-7 приведено большинство общеупотребительных префиксов имен функций в компонентах исполнительной системы. B каждом из таких компонентов также используются слегка модифицированные префиксы, обозначающие внутренние функции: либо за первой буквой префикса указывается / (от internal),либо префикс заканчивается на букву p(от private).Так, Kiотносится к внутренним функциям ядра, a Psp- к внутренним функциям поддержки процессов.
Понимая схему именования системных процедур Windows, расшифровывать имена экспортируемых функций гораздо легче. Общий формат выглядит так:
‹префикс›‹операция›‹объект›
где префикс -внутренний компонент, экспортирующий процедуру, операция- название операции, выполняемой над объектом или ресурсом, а объект- объект, над которым проводится эта операция.
Например, ExAllocatePoolWithTagявляется процедурой поддержки исполнительной системы, которая выделяет память из пула подкачиваемых или неподкачиваемых страниц. KeInitializeThreadпредставляет собой процедуру для создания и инициализации объекта ядра «поток».
Системные процессы
B каждой системе Windows выполняются перечисленные ниже процессы. (Два из них, IdIe и System, не являются процессами в строгом смысле этого слова, поскольку они не выполняют какой-либо код пользовательского режима.)
(o)Процесс IdIe (включает по одному потоку на процессор для учета времени простоя процессора).
(o)Процесс System (содержит большинство системных потоков режима ядра).
(o)Диспетчер сеансов (Smss.exe).
(o)Подсистема Windows (Csrss.exe).
(o)Процесс входа в систему (Winlogon.exe).
(o)Диспетчер управления сервисами (Services.exe) и создаваемые им дочерние процессы сервисов (например, универсальный процесс для хостинга сервисов, Svchost.exe).
(o)Серверный процесс локальной аутентификации (Lsass.exe).
Чтобы понять взаимоотношения этих процессов, полезно просмотреть «дерево» процессов, отражающее связи между родительскими и дочерними процессами. Увидев, кем создается тот или иной процесс, вам будет легче понять, откуда берется каждый процесс. Ha рис. 2-6 показана часть экранного снимка дерева процессов с комментариями по нескольким первым процессам. (Process Explorer позволяет добавлять комментарии для индивидуальных процессов и выводить их как дополнительную колонку в окне.)
B следующих разделах поясняются основные системные процессы, перечисленные на рис. 2-6. Хотя в этих разделах дается краткое описание последовательности запуска данных процессов, подробно все этапы загрузки Windows рассматриваются в главе 5.
Процесс IdIe
Первый процесс, показанный на рис. 2-6, является процессом простоя системы (system idle process). Как будет показано в главе 6, процессы идентифицируются по именам их образов. Однако этот процесс (как и процесс System) не выполняет реальный код пользовательского режима (в том смысле, что в каталоге \Windows нет «System IdIe Process.exe»). Кроме того, разные утилиты из-за особенностей реализации по-разному именуют его. B таблице 2-8 приводится несколько имен процесса IdIe (с идентификатором 0); подробнее о нем рассказывается в главе 6.
A теперь рассмотрим системные потоки и предназначение каждого системного процесса, выполняющего реальный код.
Прерывания и DPC
Две строки, помеченные как Interrupts и DPCs, отражают время, затраченное на обслуживание прерываний и обработку отложенных вызовов процедур (deferred procedure calls, DPC). Эти механизмы объясняются в главе 3. Заметьте: хотя Process Explorer показывает эти строки в списке процессов, они не имеют отношения к процессам. Они выводятся потому, что ведут учет процессорного времени, не выделенного какому-либо процессу. Ho Task Manager (Диспетчер задач) рассматривает время, затраченное на обработку преры-
ваний и DPC, как время простоя системы. Поэтому система, занятая интенсивной обработкой прерываний, будет выглядеть в Task Manager так, будто она ничем не занимается.
Процесс System и его потоки
Процесс System (с идентификатором 8 в Windows 2000 и идентификатором 4 в Windows XP и Windows Server 2003) служит носителем особых потоков, работающих только в режиме ядра, - системных потоков режима ядра(kernel-mode system threads). У системных потоков имеются все атрибуты и контексты обычных потоков пользовательского режима (например, контекст оборудования, приоритет и т. д.), но они отличаются тем, что выполняются только в режиме ядра внутри системного кода, загруженного в системное пространство, - будь то Ntoskrnl.exe или какой-либо драйвер устройства. Кроме того, у системных потоков нет адресного пространства пользовательского процесса, и поэтому нужная им динамическая память выделяется из куч памяти операционной системы, например из пула подкачиваемых или неподкачиваемых страниц.
Системные потоки создаются функцией PsCreateSystemThread(документирована в DDK), вызываемой только в режиме ядра. Windows, как и драйверы устройств, создает системные потоки при инициализации системы для выполнения действий, требующих получения контекста потока, например для выдачи и ожидания запросов на ввод-вывод или опроса устройства. Скажем, диспетчер памяти использует системные потоки для реализации таких функций, как запись измененных страниц в страничный файл (page file) или в спроецированные файлы, загрузки процессов в память или выгрузки из нее и т. д. Ядро создает системный поток под названием «диспетчер настройки баланса» (balance set manager), активизируемый раз в секунду для инициации при необходимости различных событий, связанных с планированием и управлением памятью. Диспетчер кэша также использует системные потоки для реализации как опережающего чтения, так и отложенной записи. Драйвер файл-сервера (Srv.sys) с помощью системных потоков отвечает на сетевые запросы ввода-вывода применительно к файлам на общих дисковых разделах, доступных в сети. Даже драйвер дисковода гибких дисков создает свой системный поток для опроса этого устройства (это повышает эффективность опроса, потому что драйвер дисковода гибких дисков, управляемый прерываниями, расходует много системных ресурсов). Подробнее о конкретных системных потоках см. главы, где рассматриваются соответствующие компоненты.
По умолчанию владельцем системных потоков является процесс System, но драйверы могут создавать системные потоки в любом процессе. Например, драйвер подсистемы Windows (Win32k.sys) создает системные потоки в процессе подсистемы Windows (Csrss.exe), чтобы облегчить доступ к данным в адресном пространстве этого процесса в пользовательском режиме.
Если вы занимаетесь поиском причин неполадок или системным анализом, полезно сопоставить выполнение индивидуальных системных потоков с создавшими их драйверами или даже с подпрограммой, содержащей соответствующий код. Так, на сильно загруженном файл-сервере процесс System скорее всего потребляет значительную часть процессорного времени. Ho для определения того, какой именно драйвер или компонент операционной системы выполняется, просто знать, что процесс System в данный момент выполняет «какой-то системный поток», недостаточно.
Так что, если в процессе System выполняются потоки, сначала определите, какие это потоки (например, с помощью оснастки Performance). Найдя такой поток (или потоки), посмотрите, в каком драйвере началось выполнение системного потока (это по крайней мере укажет на наиболее вероятного создателя потока), либо проанализируйте стек вызовов (или хотя бы текущий адрес) интересующего вас потока, что позволит определить, в каком месте он сейчас выполняется.
Оба этих метода демонстрируются следующими экспериментами.
ЭКСПЕРИМЕНТ: идентификация системных потоков в процессе System
Вы можете убедиться, что потоки внутри процесса System должны быть потоками режима ядра, поскольку стартовый адрес каждого из них больше адреса начала системного пространства (которое по умолчанию начинается с 0x80000000, если система загружена без параметра /3GB в Boot.ini). Кроме того, обратив внимание на процессорное время, выделяемое этим потокам, вы увидите, что они занимают процессорное время только при выполнении в режиме ядра. Чтобы определить драйвер, создавший системный поток, найдите стартовый адрес потока (с помощью Pviewer.exe) и ищите драйвер с базовым адресом, ближайшим (с меньшей стороны) к этому стартовому адресу. Утилита Pstat в конце своих выходных данных, как и команда !driversотладчика ядра, сообщает базовые адреса каждого загруженного драйвера устройства.
Чтобы быстро найти текущий адрес потока, воспользуйтесь командой !stacks 0отладчика ядра. Ниже приводится образец вывода, полученный на работающей системе с помощью LiveKd.
B первом столбце выводятся идентификаторы процесса и потока (в виде «Идентификатор процесса. Идентификатор потока»). Bo втором сообщается текущий адрес потока, в третьем - состояние потока: ожидает, готов или выполняется (о состояниях потоков см. главу 6). B последнем столбце показывается адрес вершины стека потока. Эта информация помогает определить драйвер, в котором началось выполнение того или иного потока. Имя функции потока в Ntoskrnl дает дополнительную подсказку о том, что именно делает поток.
Однако, если выполняемый поток является одним из рабочих потоков системы (ExpWorkerThread), вы не сможете точно сказать, что он делает, поскольку любой драйвер может давать задания рабочему потоку системы. B этом случае единственный выход - поставить точку прерывания в ExQueueWorkItem.По достижении этой точки введите !dso work_queue_item esp+4 .Эта команда даст вам первый аргумент функции ExQueueWorkItem,представляющий собой указатель на структуру рабочего элемента, которая в свою очередь содержит адрес процедуры рабочего потока, вызываемой в его контексте. B качестве альтернативы можно использовать команду kотладчика ядра, которая сообщает текущее содержимое стека вызовов. A это подскажет, какой драйвер отправил задание рабочему потоку.
ЭКСПЕРИМЕНТ: увязка системного потока с драйвером устройства
B этом эксперименте мы посмотрим, как увязать активность процессора в процессе System с системным потоком (и драйвером, к которому он относится), вызывающим эту активность. Это важно: чтобы по-настоящему понять, что происходит, нужно перейти на уровень потоков процесса System. B данном случае мы вызовем активность системного потока, создав нагрузку файлового сервера на компьютере. (Драйвер файл-сервера Srv.sys создает системные потоки для обработки входящих запросов на файловый ввод-вывод. Подробнее об этом компоненте см. главу 13.)
1. Откройте окно командной строки.
2. Создайте список всех каталогов на диске С, используя сетевой путь для доступа к этому диску. Например, если имя вашего компьютера - COMPUTERl, введите dir \\computerl\c$ /s.(Ключ /sзаставляет перечислять все подкаталоги.)
3. Запустите Process Explorer и дважды щелкните процесс System.
4. Откройте вкладку Threads.
5. Отсортируйте список по столбцу CSwitch Delta (разница по числу переключений контекста). Вы должны увидеть один или более потоков в Srv.sys, как показано на следующей иллюстрации.
Если вы видите работающий системный поток и не уверены, какой это драйвер, нажмите кнопку Module, которая открывает окно свойств для файла. Например, нажатие кнопки Module при выбранном, как на предыдущей иллюстрации, потоке в Srv.sys выводит результаты в следующем окне.
Диспетчер сеансов (Smss)
Диспетчер сеансов (Session Manager) ( \Windows\System32\Smss.exe) является первым процессом пользовательского режима, создаваемым в системе. Он порождается системным потоком режима ядра, отвечающим за последний этап инициализации исполнительной системы и ядра.
Диспетчер сеансов отвечает за некоторые важные этапы запуска Windows, такие как создание дополнительных страничных файлов, выполнение отложенных операций по копированию, переименованию и удалению файлов, а также создание системных переменных окружения. Он также запускает процессы подсистем (обычно только Csrss.exe) и Winlogon, который в свою очередь создает остальные системные процессы.
Значительная часть сведений о конфигурации, хранящихся в реестре и используемых при инициализации Smss, находится в HKLM\SYSTEM\Current-ControlSet\Control\Session Manager. Некоторые из этих данных поясняются в главе 5 в разделе по Smss. (Более подробное описание разделов и параметров см. в справочном файле Regentry.chm из ресурсов Windows 2000).
После выполнения этих этапов инициализации главный поток Smss переходит к бесконечному ожиданию описателей процессов Csrss и Winlogon. Так как от них зависит функционирование Windows, при неожиданном завершении любого из них Smss вызывает крах системы (с кодом STATUSSYSTEM_ PROCESS_TERMINATED, или 0xC000021A). Smss также ожидает запросы на загрузку, события отладки и запросы на запуск новых сеансов сервера терминала. (Описание служб терминала см. в главе 1.)
Сеанс Terminal Services создается Smss. Когда Smss получает запрос на создание сеанса, он сначала вызывает NtSetSystemInformationс запросом на настройку сеансовых структур данных режима ядра. Это приводит к вызову внутренней функции диспетчера памяти MmSessionCreate,настраивающей виртуальное адресное пространство сеанса, которое будет содержать пул подкачиваемой памяти для сеанса и сеансовые структуры данных, создаваемые подсистемой Windows (а точнее, ее частью, работающей в режиме ядра), а также другими драйверами устройств. (Детали см. в главе 7). Затем Smss создает экземпляр Winlogon и Csrss для данного сеанса.
Winlogon, LSASS и Userinit
Процесс входа BWindows ( \Windows\System32\Winlogon.exe) обрабатывает интерактивный вход пользователя в систему и выход из нее. При нажатии комбинации клавиш SAS (secure attention sequence) Winlogon получает уведомление о запросе пользователя на вход в систему. По умолчанию SAS в Windows представляет собой комбинацию клавиш Ctrl+Alt+Del. Назначение SAS - защита пользователя от программ перехвата паролей, имитирующих процесс входа в систему, так как эту комбинацию клавиш нельзя перехватить в приложении пользовательского режима.
Идентификация и аутентификация при входе в систему реализованы в заменяемой DLL под названием GINA (Graphical Identification and Authentication). Стандартная GINA Windows, Msgina.dll, реализует интерфейс для входа в систему по умолчанию. Однако разработчики могут включать свои GINA DLL, реализующие другие механизмы аутентификации и идентификации вместо стандартного метода Windows на основе проверки имени и пароля пользователя - например, на основе распознавания образцов голоса. Кроме того, Winlogon может загружать дополнительные DLL компонентов сетевого доступа для дальнейшей аутентификации. Эта функция позволяет нескольким компонентам доступа к сетям единовременно собирать все необходимые регистрационные данные в процессе обычного входа в систему.
После ввода имя и пароль пользователя посылаются для проверки серверному процессу локальной аутентификации (local security authentication server process, LSASS) ( \Windows\System32\Lsass.exe, описываемому в главе 8). LSASS вызывает соответствующую функциональность (реализованную в виде DLL) для проверки соответствия введенного пароля с тем, что хранится в активном каталоге или SAM (части реестра, содержащей определения пользователей и групп).
После успешной аутентификации LSASS вызывает какую-либо функцию в мониторе состояния защиты (например , NtCreateToken),чтобы сгенерировать объект «маркер доступа» (access token object), содержащий профиль безопасности пользователя. Впоследствии Winlogon использует его для создания начального процесса оболочки. Информация о начальном процессе (или процессах) хранится в параметре Userinit в разделе реестра HKLM\ SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon. (По умолчанию начальным процессом считается Userinit.exe, но в списке может быть более одного образа.)
Userinit выполняет некоторые действия по инициализации пользовательской среды (например, запускает сценарии регистрации и активизирует групповые политики), а затем ищет в реестре параметр Shell (в указанном выше разделе Winlogon) и создает процесс для запуска определенной системной оболочки (по умолчанию - Explorer.exe). После этого процесс Userinit завершается. Вот почему для Explorer.exe не показывается родительский процесс - он уже завершился. Иначе говоря, Explorer является «внучатым» процессом Winlogon. (Имена процессов, чьи родительские процессы уже завершены, в списке Tlist выравниваются по левому краю.)
Winlogon активен не только при входе и выходе пользователя, но и при перехвате ввода SAS с клавиатуры. Например, когда вы нажимаете Ctrl+Alt+ DeI после входа в систему, Winlogon открывает диалоговое окно Windows Security (Безопасность Windows), предлагающее на выбор выход из системы, запуск Task Manager, блокировку рабочей станции, завершение работы системы и т. д.
Полное описание этапов процесса входа см. в разделе «Smss, Csrss и Winlogon» главы 5. Подробнее об аутентификации см. главу 8. Подробнее о вызываемых функциях интерфейса LSASS (чьи имена начинаются с Lsd)см. документацию Platform SDK.
Диспетчер управления сервисами (SCM)
Вспомните, что термин «сервисы» в Windows обозначает как серверные процессы, так и драйверы устройств. B этом разделе обсуждаются сервисы, являющиеся процессами пользовательского режима. Они похожи на демоны UNIX или обособленные процессы VMS в том смысле, что могут быть сконфигурированы на автоматический запуск при загрузке системы, не требуя интерактивного входа. Их также можно запустить вручную, например, с помощью оснастки Services (Службы) или вызовом Windows-функции StartSer-vice.Как правило, сервисы не взаимодействуют с вошедшим в систему пользователем, хотя при особых условиях это возможно (см. главу 4).
Этими сервисами управляет специальный системный процесс, диспетчер управления сервисами (service control manager) (\Windows\System32\Servi-ces.exe), отвечающий за запуск, остановку процессов сервисов и взаимодействие с ними. Сервисы представляют собой просто Windows-образы исполняемых программ, вызывающие особые Windows-функции для взаимодействия с диспетчером управления сервисами и с его помощью выполняющие такие операции, как регистрация успешного запуска сервиса, ответы на запросы о состоянии, приостановку или завершение работы сервиса. Сервисы определяются в разделе реестра HKLM\SYSTEM\CurrentControlSet\Services. Сведения о подразделах и параметрах, относящихся к сервисам, см. в справочном файле Regentry.chm в ресурсах Windows.
Учтите, что у сервисов есть три имени: имя процесса, выполняемого в системе, внутреннее имя в реестре и так называемое отображаемое имя (display name), которое можно увидеть в оснастке Services (Службы). (He у каждого сервиса есть отображаемое имя, и в случае его отсутствия используется внутреннее имя.) Сервисы Windows также содержат поле описания, где находится более подробная информация о том, что делает конкретный сервис.
Чтобы выяснить, какие именно сервисы содержатся в том или ином процессе, введите команду tlist /s.Ho заметьте, что иногда один процесс совместно используется несколькими сервисами. Код типа в реестре позволяет узнать, какие сервисы имеют собственные процессы и какие из них делят процессы с другими сервисами данного образа файла.
B виде сервисов реализуются некоторые компоненты Windows, например диспетчер очереди печати (спулер), журнал системных событий, планировщик задач, а также ряд сетевых компонентов.
ЭКСПЕРИМЕНТ: вывод списка установленных сервисов
Чтобы вывести список установленных сервисов (служб), дважды щелкните значок Administrative Tools (Администрирование) в окне Control Panel (Панель управления) и выберите Services (Службы). Вы должны увидеть что-нибудь в таком роде:
Для просмотра детальных сведений о сервисе щелкните правой кнопкой мыши имя сервиса и выберите команду Properties (Свойства). Ниже показан пример окна свойств для службы Print Spooler (Диспетчер очереди печати).
Обратите внимание, что поле Path To Executable (Исполняемый файл) указывает на программу, включающую данный сервис. Помните, что некоторые сервисы разделяют процессы с другими сервисами, поэтому число сервисов и используемых ими процессов не всегда находится в соотношении «один к одному».
ЭКСПЕРИМЕНТ: просмотр сервисов внутри сервисных процессов
Process Explorer выделяет процессы, которые являются хостами одного и более сервисов. (Для настройки поведения Process Explorer выберите Configure Highlighting в меню Options.) Дважды щелкнув процесс - хост сервисов, вы откроете вкладку Services, где перечисляются сервисы внутри этого процесса. При этом по каждому сервису выводится имя раздела реестра, где определен данный сервис, отображаемое имя, видимое администратору, и текст описания для этого сервиса (если такой текст есть). Например, в Windows XP список сервисов в процессе Svchost.exe, выполняемом под учетной записью System, выглядит следующим образом.
Подробнее о сервисах рассказывается в главе 4.
Резюме
B этой главе мы познакомились с общими аспектами системной архитектуры Windows. Мы также рассмотрели ключевые компоненты Windows и принципы их взаимодействия. B следующей главе будет подробнее рассказано о базовых системных механизмах, на которые опираются эти компоненты, в том числе о синхронизации и диспетчере объектов.
Г Л A B A 3 Системные механизмы
B Microsoft Windows существует несколько базовых механизмов, которыми пользуются компоненты режима ядра: исполнительная система (executive), ядро и драйверы устройств. B этой главе описываются следующие системные механизмы (а также способы их использования):
(o)диспетчеризация ловушек (trap dispatching), в том числе прерываний, DPC (deferred procedure call), APC (asynchronous procedure call), исключений и системных сервисов;
(o)диспетчер объектов исполнительной системы;
(o)синхронизация, в том числе спин-блокировки, объекты диспетчера ядра (kernel dispatcher objects) и реализация механизмов ожидания;
(o)системные рабочие потоки;
(o)различные механизмы вроде поддержки глобальных флагов Windows;
(o)LPC (local procedure call);
(o)Kernel Event Tracing;
(o)Wow64.
Диспетчеризация ловушек
Прерывания и исключения - такие ситуации в операционной системе, в которых нормальный поток выполнения кода процессором прерывается. Эти ситуации обнаруживаются как программным, так и аппаратным обеспечением. Термин ловушка(trap) относится к механизму, благодаря которому при прерывании или исключении процессор перехватывает контроль над выполняемым потоком и передает управление определенной части операционной системы. B Windows процессор передает управление обработчику ловушек(trap handler) - функции, специфичной для конкретного прерывания или исключения. Рис. 3-1 иллюстрирует некоторые ситуации, в которых активизируются обработчики ловушек.
Ядро различает прерывания и исключения: прерывание(interrupt) является асинхронным событием (т. е. оно может произойти в любой момент независимо от текущих команд, выполняемых процессором). Прерывания в основном генерируются устройствами ввода-вывода и таймерами. Их можно включать и отключать. Исключение(exception), напротив, представляет собой синхронное событие, являющееся результатом выполнения конкретной команды. Повторный запуск программы в аналогичных условиях с теми же данными позволит воспроизвести исключение. Примерами исключений могут служить нарушения доступа (ошибки защиты памяти), выполнение некоторых команд отладчика, а также попытки деления на нуль. Ядро также считает исключениями вызовы системных сервисов (хотя с точки зрения технической реализации это системные ловушки).
Прерывания и исключения можно генерировать как программно, так и аппаратно. Например, исключение «bus error» (ошибка шины) возникает из-за аппаратной ошибки, а причиной исключения «divide-by-zero» (деление на нуль) является ошибка в программе. Аналогичным образом прерывания могут генерироваться устройствами ввода-вывода или самим ядром (такие программные прерывания, как, например, APC или DPC).
При аппаратном прерывании или исключении процессор записывает статусную информацию в стек ядра для прерванного потока, чтобы впоследствии можно было вернуться к исходной точке в потоке управления и продолжить выполнение команд так, будто ничего не произошло. Если поток выполнялся в пользовательском режиме, Windows переключается на стек режима ядра для потока. Затем создает в стеке ядра прерванного потока фрейм ловушки(trap frame), в котором сохраняет информацию о состоянии потока. Фрейм ловушки является подмножеством полного контекста потока (см. главу 6), и вы можете просмотреть его определение, введя в отладчике ядра команду