Внутреннее устройство Windows. 7-е изд.

Глава 1. Концепции и средства

В этой главе будут представлены ключевые концепции и термины операционной системы (ОС) Microsoft Windows: Windows API, процессы, программные потоки, виртуальная память, режим ядра и пользовательский режим, объекты, дескрипторы, безопасность и реестр. Также мы рассмотрим некоторые средства, которые могут использоваться для исследования внутреннего строения Windows, например отладчик ядра, системный монитор и важнейшие программы из пакета Windows Sysinternals (). Кроме того, мы объясним, как использовать пакеты Windows Driver Kit (WDK) и Windows Software Development Kit (SDK) для получения дальнейшей информации о внутреннем строении Windows.

После прочтения этой главы проверьте себя: все ли вы поняли? Если вы не усвоите материал этой главы, то не поймете материал оставшейся части книги.

Версии операционной системы Windows

В книге рассматриваются самые последние версии ОС Microsoft Windows для клиента и сервера: Windows 10 (32-разрядная для x86 и ARM, 64-разрядная для x64) и Windows Server 2016 R2 (существует только в 64-разрядной версии). Материал книги относится ко всем версиям, если в тексте явно не указано обратное. Для справки в табл. 1.1 перечислены названия продуктов семейства Windows, их внутренние номера версий и даты релиза.

Начиная с Windows 7, нумерация версий перестала быть очевидной. Системе был присвоен номер версии 6.1 вместо 7. Из-за популярности Windows XP, когда в Windows Vista номер версии был повышен до 6.0, в некоторых приложениях проверка версии ОС стала работать некорректно — разработчики проверяли, что основная версия больше или равна 5, а дополнительная версия больше или равна 1; в Windows Vista это условие не выполнялось. Компания Microsoft усвоила урок и решила оставить основную версию 6 с повышением дополнительной версии до 2 (больше 1), чтобы свести к минимуму подобные несовместимости. Впрочем, в Windows 10 номер версии был обновлен до 10.0.

Таблица 1.1. Релизы операционной системы Windows

Название продукта

Внутренний номер версии

Дата релиза

Windows NT 3.1

3.1

июль 1993 г.

Windows NT 3.5

3.5

сентябрь 1994 г.

Windows NT 3.51

3.51

май 1995 г.

Windows NT 4.0

4.0

июль 1996 г.

Windows 2000

5.0

декабрь 1999 г.

Windows XP

5.1

август 2001 г.

Windows Server 2003

5.2

март 2003 г.

Windows Server 2003 R2

5.2

декабрь 2005 г.

Windows Vista

6.0

январь 2007 г.

Windows Server 2008

6.0 (Service Pack 1)

март 2008 г.

Windows 7

6.1

октябрь 2009 г.

Windows Server 2008 R2

6.1

октябрь 2009 г.

Windows 8

6.2

октябрь 2012 г.

Windows Server 2012

6.2

октябрь 2012 г.

Windows 8.1

6.3

октябрь 2013 г.

Windows Server 2012 R2

6.3

октябрь 2013 г.

Windows 10

10.0 (сборка 10240)

июль 2015 г.

Windows 10 версия 1511

10.0 (сборка 10586)

ноябрь 2015 г.

Windows 10 версия 1607 (Anniversary Update)

10.0 (сборка 14393)

июль 2016 г.

Windows Server 2016

10.0 (сборка 14393)

октябрь 2016 г.

ПРИМЕЧАНИЕ Начиная с Windows 8, функция Windows API GetVersionEx по умолчанию возвращает номер версии 6.2 (Windows 8) независимо от фактической версии ОС. (Эта функция также объявлена устаревшей.) Это сделано для того, чтобы свести к минимуму проблемы совместимости; кроме того, такой подход показывает, что проверка версии ОС в большинстве случаев не является оптимальным решением. Дело в том, что некоторые компоненты могут устанавливаться «раньше времени», без согласования с официальным выпуском Windows. Тем не менее, если вам нужно узнать фактическую версию ОС, вы можете получить ее при помощи функции VerifyVersionInfo или более новых вспомогательных API проверки версий: IsWindows8OrGreater, IsWindows8Point1OrGreater, IsWindows10OrGreater, IsWindowsServer и т.д. Кроме того, совместимость с разными операционными системами ОС может быть обозначена в манифесте исполняемого файла, что приводит к изменению результатов вызова этой функции. (За подробностями обращайтесь к разделу «Загрузчик образа» главы 3.)

Для просмотра информации о версии Windows можно воспользоваться программой командной строки ver или ее графической версией winver. Вот как выглядит результат выполнения winver в Windows 10 Enterprise версии 1511:

1-3.tif 

Графическая версия также выводит номер сборки Windows (10586.218 в данном примере); он может быть полезен для участников программы предварительной оценки Windows Insiders (зарегистрировавшихся для получения ранних ознакомительных версий Windows). Информация может пригодиться и для управления обновлениями безопасности, потому что в ней указан уровень установленного исправления.

Windows 10 и будущие версии Windows

С выходом Windows 10 компания Microsoft объявила, что обновление Windows отныне пойдет в более быстром темпе. Официальной версии «Windows 11» не будет; вместо этого Windows Update (или другая модель корпоративного обслуживания) будет обновлять существующую версию Windows 10 до новой версии. На момент написания книги произошло два обновления: в ноябре 2015 года (известное как «версия 1511» по году и месяцу) и в июле 2015 (версия 1607, известная под маркетинговым названием «Anniversary Update»).

ПРИМЕЧАНИЕ На внутреннем уровне Microsoft продолжает строить версии Windows «волнами». Например, исходной версии Windows 10 было присвоено кодовое название Threshold 1, тогда как обновление в ноябре 2015 года называлось Threshold 2. Следующие три фазы обновлений назывались Redstone 1 (версия 1607), Redstone 2 и Redstone 3.

Windows 10 и OneCore

За прошедшие годы появилось несколько разновидностей Windows. Кроме «массовых» версий Windows, работающих на PC, существует ответвление Windows 2000 для игровой приставки Xbox 360. Система Windows Phone 7 использует версию на базе Windows CE (ОС реального времени от Microsoft). Конечно, сопровождение и расширение всех этих кодовых баз создавало немало сложностей, поэтому в Microsoft решили свести воедино разные ядра и базовые двоичные модули платформенной поддержки. Все началось с использования в Windows 8 и Windows Phone 8 общего ядра (а в Windows 8.1 и Windows Phone 8.1 — единого Windows Runtime API). В Windows 10 слияние завершилось; единая платформа, получившая название OneCore, работает на PC, смартфонах, игровой приставке Xbox One, HoloLens и устройствах IoT (Internet of Things), таких как Raspberry Pi 2.

Понятно, что все эти форм-факторы устройств очень сильно отличаются друг от друга. Некоторые функции на ряде устройств просто отсутствуют. Например, поддержка мыши или физической клавиатуры на устройстве HoloLens не имеет смысла, поэтому вряд ли можно ожидать наличия соответствующих компонентов в версии Windows 10 для таких устройств. Однако ядро, драйверы и двоичные файлы базовой платформы фактически остаются неизменными (с настройками на уровне реестра и/или политики по соображениям производительности или другим причинам). Пример такой политики приведен в разделе «Наборы API-функций» главы 3 «Процессы и задания».

В книге будет рассматриваться внутреннее строение ядра OneCore независимо от того, на каком устройстве оно выполняется. Тем не менее описанные в книге эксперименты предполагают использование настольного компьютера с мышью и клавиатурой, и воспроизвести их на других устройствах (скажем, на телефоне или Xbox One) непросто, а иногда и официально невозможно.

Фундаментальные концепции и термины

В этом разделе представлены фундаментальные концепции Windows, необходимые для понимания материала остальных глав книги. Многие концепции, такие как программные потоки и виртуальная память, подробно рассматриваются в последующих главах.

Windows API

Windows API (Application Programming Interface) — программный интерфейс пользовательского режима для ОС семейства Windows. До появления 64-разрядных версий Windows программный интерфейс 32-разрядных версий ОС Windows назывался Win32 API в отличие от исходного 16-разрядного Windows API, программного интерфейса для исходных 16-разрядных версий Windows. В этой книге термин Windows API относится как к 32-разрядным, так и 64-разрядным программным интерфейсам Windows.

ПРИМЕЧАНИЕ Иногда мы используем термин Win32 API вместо Windows API. В любом случае он все равно относится как к 32-разрядным, так и к 64-разрядным версиям.

ПРИМЕЧАНИЕ Описание Windows API содержится в документации Windows SDK. (См. раздел «Windows SDK» далее в этой главе.) Документация доступна бесплатно по адресу . Также она включается во все уровни подписки MSDN (Microsoft Developer Network), программы поддержки разработчиков от компании Microsoft. Отличное введение в программирование с использованием базового Windows API представлено в книге «Windows via C/C++, Fifth Edition» Джеффри Рихтера (Jeffrey Richter) и Кристофа Насарра (Christophe Nasarre) (Microsoft Press, 2007).

Разновидности Windows API

Изначально Windows API состоял только из функций в стиле C. Сегодня разработчикам доступны тысячи функций. Выбор языка C был естественным на момент появления Windows, потому что он был своего рода «наименьшим общим кратным» (т. е. написанный на нем код также мог использоваться из других языков) и он был достаточно низкоуровневым для предоставления сервиса ОС. Обратной стороной было огромное количество функций в сочетании с недостаточной последовательностью выбора имен и отсутствием логических группировок (вроде пространств имен C++). Эти сложности привели к тому, что в некоторых новых API используется другой механизм — модель COM (Component Object Model, «модель составного объекта»).

Технология COM изначально создавалась для того, чтобы приложения Microsoft Office могли взаимодействовать друг с другом и передавать данные между документами (например, чтобы в документ Word можно было вставить диаграмму Excel или презентацию PowerPoint). Эта функциональность получила название OLE (Object Linking and Embedding, «связывание и внедрение объектов»). Сначала технология OLE была реализована на базе старого механизма передачи сообщений в Windows, который назывался DDE (Dynamic Data Exchange, «динамический обмен данными»). Технология DDE обладала рядом непреодолимых ограничений, поэтому был разработан новый коммуникационный механизм — COM. Более того, в первом варианте, который был представлен около 1993 года, технология COM изначально называлась OLE 2.

COM базируется на двух основополагающих принципах. Во-первых, клиенты взаимодействуют с объектами (которые иногда называются серверными объектами COM) через интерфейсы — четко определенные контракты с набором логически связанных методов, сгруппированных посредством механизма диспетчеризации по виртуальным таблицам (этот же механизм обычно применяется компиляторами C++ для реализации диспетчеризации виртуальных функций). Таким образом обеспечивается двоичная совместимость и снимаются проблемы с декорированием имен компилятором. Соответственно, такие методы могут вызываться из многих других языков (и компиляторов), включая C, C++, Visual Basic, языки .NET, Delphi и т.д. Второй принцип — динамическая загрузка компонентов (вместо статической компоновки с клиентом).

Термин «сервер COM» обычно относится к DLL-библиотеке или исполняемому файлу (EXE), в котором реализованы классы COM. COM также содержит ряд важных функций, связанных с безопасностью, межпроцессным маршалингом, потоковой моделью и т.д. Подробное знакомство с COM выходит за рамки книги; отличное описание можно найти в книге Дона Бокса (Don Box) «Essential COM» (Addison-Wesley, 1998).

ПРИМЕЧАНИЕ Среди примеров API, доступ к которым осуществляется через COM, можно назвать DirectShow, Windows Media Foundation, DirectX, DirectComposition, WIC (Windows Imaging Component) и BITS (Background Intelligent Transfer Service).

Windows Runtime

В Windows 8 появились новый API и исполнительная среда поддержки Windows Runtime (иногда используется сокращение WinRT — не путайте с Windows RT, версии ОС Windows на базе ARM, поддержка которой была прекращена). Windows Runtime состоит из платформенных сервисов, предназначенных для разработчиков приложений Windows Apps (ранее также использовались термины Metro Apps, Modern Apps, Immersive Apps и Windows Store Apps). Приложения Windows Apps подходят для разных форм-факторов устройств, от миниатюрных IoT-устройств до телефонов, планшетов, ноутбуков, настольных систем, и даже таких устройств, как Xbox One и Microsoft HoloLens.

С точки зрения API платформа WinRT строится на базе COM, добавляя в базовую инфраструктуру COM различные расширения. Например, в WinRT доступны полные метаданные типов (хранящиеся в файле WINMD и основанные на формате метаданных .NET), расширяющие аналогичную концепцию библиотек типов в COM. С точки зрения архитектуры API она обладает намного большей целостностью, чем классические функции Windows API: в ней реализованы иерархии пространств имен, последовательная схема назначения имен и паттерны программирования.

Приложения Windows Apps строятся по новым правилам и не похожи на привычные приложения Windows (которые теперь называются настольными приложениями Windows или классическими приложениями Windows). Эти правила описаны в главе 9 «Механизмы управления» части 2.

Отношения между различными API и приложениями не столь прямолинейны. Настольные приложения могут использовать подмножество WinRT API. И наоборот, приложения Windows Apps могут использовать подмножество Win32 и COM API. За подробной информацией о том, какие API доступны для каждой платформы приложений, обращайтесь к документации MSDN.

Однако обратите внимание на то, что на базовом двоичном уровне WinRT API все равно строится на основе унаследованных двоичных файлов и API Windows, даже если доступность некоторых API не документирована и официально не поддерживается. Это не новый «машинный» API для системы, а ситуация напоминает то, как .NET строится на основе традиционного Windows API.

Приложения, написанные на C++, C# (и других языках .NET) и JavaScript, могут легко использовать WinRT API благодаря языковым проекциям, разработанным для этих платформ. Для C++ компания Microsoft создала нестандартное расширение C++/CX, которое упрощает работу с типами WinRT. Обычная прослойка взаимодействия COM для .NET (с некоторыми расширениями исполнительной среды) позволяет любому языку .NET использовать WinRT API естественно и просто, как если бы это была чистая среда .NET. Чтобы разработчики JavaScript могли работать с WinRT, было разработано расширение WinJS, хотя для построения пользовательских интерфейсов разработчикам JavaScript все равно приходится использовать HTML.

ПРИМЕЧАНИЕ Хотя разметка HTML может использоваться в приложениях Windows Apps, они все равно остаются локальными клиентскими приложениями, а не веб-приложениями, загружаемыми с веб-сервера.

.NET Framework

.NET Framework является частью Windows. В табл. 1.2 перечислены версии .NET Framework, устанавливаемые в составе разных версий Windows. Впрочем, новые версии .NET Framework могут устанавливаться и в старых версиях ОС.

Таблица 1.2. Версии .NET Framework, устанавливаемые по умолчанию в Windows

Версия Windows

Версия .NET Framework

Windows 8

4.5

Windows 8.1

4.5.1

Windows 10

4.6

Windows 10 версия 1511

4.6.1

Windows 10 версия 1607

4.6.2

.NET Framework состоит из двух основных компонентов:

• CLR (Common Language Runtime). Исполнительная среда .NET; включает JIT-компилятор (Just-In-Time) для преобразования инструкций языка CIL (Common Intermediate Language) в низкоуровневый язык машинных команд процессора, уборщик мусора, систему проверки типов, безопасность обращения к коду и т.д. Среда реализована в виде внутрипроцессного сервера COM (DLL) и использует различные средства, предоставляемые Windows API.

• .NET Framework Class Library (FCL). Обширная подборка типов, реализующих функциональность, часто используемую в клиентских и серверных приложениях, – средства пользовательского интерфейса, поддержка сети, работа с базами данных и т.д.

Среда .NET Framework, предоставляющая эти и другие возможности, включая высокоуровневые языки программирования (C#, Visual Basic, F#) и вспомогательные средства, повышает производительность труда разработчика, а также безо­пасность и надежность приложений. На рис. 1.1 изображены отношения между .NET Framework и ОС Windows.

345244.png 

Рис. 1.1. Отношения между .NET и ОС Windows

Службы, функции и процедуры

Некоторые термины в документации пользователя и разработчика Windows имеют разный смысл в разных контекстах. Например, словом «служба» (service) может обозначаться код ОС, который может вызываться извне, драйвер устройства или серверный процесс. В следующем списке указано, какой смысл имеют некоторые термины из книги.

• Функции Windows API. Документированные, открытые для вызова процедуры Windows API. Примеры — CreateProcess, CreateFile и GetMessage.

• Системные вызовы (низкоуровневые системные функции). Недокументированные сервисные функции ОС, которые могут вызываться из пользовательского режима. Например, NtCreateUserProcess — внутренняя системная функция, вызываемая функцией Windows CteateProcess для создания нового процесса.

• Вспомогательные функции ядра (процедуры). Подпрограммы ОС Windows, которые могут вызываться только из режима ядра (см. далее в этой главе). Например, процедура ExAllocatePoolWithTag вызывается драйверами устройств для выделения памяти из системного пула Windows (так называемой кучи).

• Службы Windows. Процессы, запускаемые диспетчером служб Windows. Например, служба планировщика задач выполняется в процессе пользовательского режима, поддерживающего команду schtasks (аналог команд UNIX at и cron). (Заметим, что хотя в системном реестре драйверы устройств Windows определяются как «службы», в книге термин в этом контексте использоваться не будет.)

• Библиотеки динамической компоновки (DLL). Подпрограммы, предназначенные для внешнего вызова и объединенные в двоичные файлы, которые могут динамически загружаться приложениями, использующими эти подпрограммы. Примеры: Msvcrt.dll (библиотека времени выполнения C) и Kernel32.dll (одна из библиотек подсистемы Windows API). Приложения и компоненты пользовательского режима Windows широко используют DLL-библиотеки. Их преимущество перед статическими библиотеками заключается в том, что DLL могут совместно использоваться приложениями; система Windows позаботится о том, чтобы в памяти находилась только одна копия кода DLL-библиотеки для всех приложений, работающих с ней. Обратите внимание: библиотечные сборки .NET компилируются в формат DLL, но без неуправляемых экспортируемых подпрограмм. Вместо этого CLR разбирает откомпилированные метаданные для обращения к соответствующим типам и членам.

Процессы

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

• закрытое виртуальное адресное пространство — множество адресов виртуальной памяти, которая может использоваться процессом;

• исполняемая программа, которая определяет первоначальный код и данные и отображается в виртуальное адресное пространство процесса;

• список открытых дескрипторов для различных системных ресурсов (семафоров, объектов синхронизации портов, файлов и т.д.), доступных для всех программных потоков в процессе;

• контекст безопасностимаркер доступа (access token), который идентифицирует пользователя, группы безопасности, привилегии, состояние виртуализации UAC (User Account Control), сеанс и ограниченное состояние учетной записи пользователя, связанное с процессом, а также идентификатор контейнера приложения и связанная с ним информация изоляции;

• идентификатор процесса — уникальный идентификатор, который является частью идентификатора клиента;

• по меньшей мере один программный поток (thread). Пустые процессы теоретически могут существовать, но особой пользы не принесут.

Существуют различные программы для просмотра (и изменения) процессов и информации процессов. Описанные ниже эксперименты показывают, какую информацию о процессах можно получить при помощи некоторых средств такого рода. Многие из этих средств включены в систему Windows, средства отладки для Windows и Windows SDK; другие являются самостоятельными программами из пакета Sysinternals. Многие программы выводят перекрывающиеся подмножества базовых данных процессов и программных потоков, которые иногда обозначаются разными именами.

Вероятно, для просмотра информации о процессах чаще всего используется диспетчер задач (Task Manager). (Выбор названия программы выглядит немного странно, так как в ядре Windows не существует понятия «задачи» (task).) Следующий эксперимент демонстрирует некоторые базовые возможности диспетчера задач.

Эксперимент: просмотр информации процессов в Диспетчере задач

Диспетчер задач, встроенный в Windows, выдает простой список процессов в системе. Диспетчер задач можно запустить четырьмя способами:

Нажмите Ctrl+Shift+Esc.

Щелкните правой кнопкой мыши на панели задач и выберите команду диспетчер задач (Start Task Manager).

Нажмите Ctrl+Alt+Del и щелкните на кнопке Запустить диспетчер задач (Start Task Manager).

Запустите исполняемый файл Taskmgr.exe.

При первом запуске диспетчер задач работает в «кратком» режиме, в котором выводятся только процессы, имеющие видимое окно верхнего уровня, как на следующем снимке экрана:

1-9.1.tif 

В этом режиме ваши возможности сильно ограничены, поэтому щелкните на кнопке Подробнее (More Details), чтобы открыть полное представление диспетчера задач. По умолчанию выбирается вкладка Процессы (Processes):

1-9.2.tif 

На вкладке Процессы (Processes) выводится список процессов, состоящий из четырех столбцов: ЦП (CPU), Память (Memory), Диск (Disk) и Сеть (Network). Чтобы добавить в список другие столбцы, щелкните правой кнопкой мыши на заголовке. Также доступны столбцы Process (Image) name, ИД процесса (Process ID), Тип (Type), Состояние (Status), Издатель (Publisher) и Командная строка (Command Line). Некоторые процессы можно дополнительно развернуть с выводом информации о видимых окнах верхнего уровня, созданных процессом.

Чтобы получить еще больше информации о процессе, щелкните на кнопке Подробнее (Details). Также можно щелкнуть правой кнопкой мыши на процессе и выбрать команду Подробнее (Go to Details), чтобы переключиться на вкладку Подробности (Details) и выбрать этот конкретный процесс.

ПРИМЕЧАНИЕ Вкладка Процессы (Processes) диспетчера задач Windows 7 приблизительно эквивалентна вкладке Подробности (Details) диспетчера задач Windows 8+. На вкладке Приложения (Applications) диспетчера задач Windows 7 выводятся видимые окна верхнего уровня, а не процессы как таковые. В новом диспетчере задач Windows 8+ эта информация теперь содержится на вкладке Процессы (Processes).

1-10.1.tif 

На вкладке Подробности (Details) также выводятся процессы, но в более компактном виде. На ней нет информации об окнах, созданных процессами, но больше столбцов с разнообразными данными.

Обратите внимание: процессы идентифицируются по имени образа, экземплярами которого они являются. В отличие от некоторых объектов Windows, процессам не могут присваиваться глобальные имена. Для вывода дополнительной информации щелкните правой кнопкой мыши на заголовке и щелкните на кнопке Выбрать столбцы (Select Columns). Открывается список столбцов, который выглядит так:

1-10.2.tif 

Некоторые важнейшие столбцы:

Потоки (Threads) — в этом столбце выводится количество программных потоков в каждом процессе. Это число обычно не меньше 1, так как невозможно напрямую создать процесс, не содержащий ни одного потока (к тому же такой процесс будет бесполезен). Если в списке присутствует процесс с 0 потоков, обычно это означает, что процесс не удается удалить по какой-либо причине — чаще всего из-за ошибки в коде драйвера.

Дескрипторы (Handles) — в этом столбце выводится количество дескрипторов объектов ядра, открытых программными потоками, выполняемыми в процессе. (Дескрипторы рассматриваются далее в этой главе, а также более подробно в главе 8 части 2.)

Состояние (Status) — с этим столбцом дело обстоит сложнее. Для процессов, не имеющих пользовательского интерфейса, в нем обычно выводится значение Выполняется (Running), хотя все потоки могут чего-то ожидать, например сигнала о состоянии объекта ядра или завершения операции ввода/вывода. Другое возможное значение — Приостановлен (Suspended) — встречается в том случае, если все потоки процесса находятся в приостановленном состоянии. Вряд ли это произойдет в результате деятельности самого процесса, хотя может быть следствием вызова для процесса недокументированной функции API NtSuspendProcess, чаще всего при помощи служебной программы (например, программы Process Explorer, описанной ниже). Для процессов, создающих пользовательский интерфейс, состояние Выполняется (Running) означает, что пользовательский интерфейс реагирует на действия пользователя. Иначе говоря, поток, создавший окно (или окна), ожидает пользовательского ввода (с технической точки зрения — очереди сообщений, связанной с потоком). Состояние приостановки возможно и без пользовательского интерфейса, но для приложений Windows Apps (на платформе Windows Runtime) приостановка обычно происходит тогда, когда приложение уходит с первого плана из-за того, что оно было свернуто пользователем. Такие процессы приостанавливаются через 5 секунд, чтобы они не поглощали ресурсы процессора или сети, а новое приложение первого плана могло получить в свое распоряжение все ресурсы машины. Это особенно важно для устройств с питанием от аккумулятора, таких как планшеты или телефоны. Эти и другие сопутствующие механизмы более подробно описаны в главе 9 части 2. Третье возможное значение в столбце Состояние (Status) — Не отвечает (Not Responding). Оно возникает в том случае, если программный поток процесса, создавший пользовательский интерфейс, не проверял свою очередь сообщений на предмет UI-событий по крайней мере 5 секунд. Процесс (а на самом деле поток, которому принадлежит окно) может быть занят работой, интенсивно загружающей процессор, или может ожидать чего-то совершенно иного (например, завершения операции ввода/вывода). В любом случае пользовательский интерфейс «зависает», а Windows сообщает об этом, затеняя такое окно (или окна) и выводя в столбце Состояние (Status) значение Не отвечает (Not Responding).

Каждый процесс также содержит идентификатор своего родительского процесса или процесса-создателя (они могут совпадать, но это не обязательно). Если родитель не существует, то информация не обновляется. Следовательно, процесс может хранить идентификатор несуществующего родителя; это не создает проблем, потому что система не полагается на актуальность этой информации. В программе Process Explorer учитывается время запуска родительского процесса, чтобы избежать связывания дочернего процесса на основании уже переназначенного идентификатора процесса. Следующий эксперимент демонстрирует это поведение.

ПРИМЕЧАНИЕ Почему процесс-родитель может не совпадать с процессом-создателем? В некоторых случаях процессы, которые на первый взгляд были созданы определенным пользовательским приложением, могут использовать участие вспомогательного процесса (процесса-брокера), отвечающего за вызовы API создания процессов. В таких случаях указание процесса-брокера в качестве создателя будет создавать путаницу (и даже ошибки при использовании наследования адресного пространства или дескрипторов), поэтому требуется «смена родителя». Один из примеров такого рода приведен в главе 7 «Безопасность».

Эксперимент: просмотр дерева процессов

Большинство служебных программ не выводит идентификаторы родителей или создателей процессов. Для получения этой информации можно воспользоваться Системным монитором (или запросить идентификатор процесса-создателя из программного кода). Также можно воспользоваться программой Tlist.exe из средств отладки Windows и запросить вывод дерева процессов при помощи ключа /t. Пример вывода команды tlist /t:

System Process (0)

System (4)

  smss.exe (360)

csrss.exe (460)

wininit.exe (524)

  services.exe (648)

    svchost.exe (736)

      unsecapp.exe (2516)

      WmiPrvSE.exe (2860)

      WmiPrvSE.exe (2512)

      RuntimeBroker.exe (3104)

      SkypeHost.exe (2776)

      ShellExperienceHost.exe (3760) Windows Shell Experience Host

      ApplicationFrameHost.exe (2848) OleMainThreadWndName

      SearchUI.exe (3504) Cortana

      WmiPrvSE.exe (1576)

      TiWorker.exe (6032)

      wuapihost.exe (5088)

    svchost.exe (788)

    svchost.exe (932)

    svchost.exe (960)

    svchost.exe (976)

    svchost.exe (68)

    svchost.exe (380)

    VSSVC.exe (1124)

    svchost.exe (1176)

      sihost.exe (3664)

      taskhostw.exe (3032) Task Host Window

    svchost.exe (1212)

    svchost.exe (1636)

    spoolsv.exe (1644)

    svchost.exe (1936)

    OfficeClickToRun.exe (1324)

    MSOIDSVC.EXE (1256)

      MSOIDSVCM.EXE (2264)

    MBAMAgent.exe (2072)

    MsMpEng.exe (2116)

    SearchIndexer.exe (1000)

      SearchProtocolHost.exe (824)

    svchost.exe (3328)

    svchost.exe (3428)

    svchost.exe (4400)

    svchost.exe (4360)

    svchost.exe (3720)

    TrustedInstaller.exe (6052)

  lsass.exe (664)

csrss.exe (536)

winlogon.exe (600)

  dwm.exe (1100) DWM Notification Window

explorer.exe (3148) Program Manager

  OneDrive.exe (4448)

  cmd.exe (5992) C:\windows\system32\cmd.exe - tlist /t

    conhost.exe (3120) CicMarshalWnd

    tlist.exe (5888)

SystemSettingsAdminFlows.exe (4608)

Отношения «родитель—потомок» в этом списке обозначаются отступами. Процессы, не имеющие «живых» родителей, выравниваются по левому краю (как explorer.exe в приведенном примере), потому что, даже если процесс-предок более высокого уровня существует, отследить его невозможно. Windows хранит только идентификатор процесса-создателя, а не ссылки на всех предков.

Число в круглых скобках — идентификатор процесса, а текст после некоторых процессов — заголовок окна, созданного процессом.

Чтобы убедиться в том, что Windows не хранит ничего, кроме идентификатора родительского процесса, выполните следующие действия:

1. Нажмите клавиши Win+R, введите команду cmd и нажмите Enter, чтобы открыть окно командной строки.

2. Введите команду title parent, чтобы сменить текст заголовка окна на Parent.

3. Введите команду start cmd, чтобы открыть другое окно командной строки.

4. Введите команду title Child во втором окне командной строки.

5. Введите команду mspaint во втором окне командной строки, чтобы запустить Microsoft Paint.

6. Вернитесь ко второму окну командной строки и введите команду exit. Обратите внимание: окно Paint остается на экране.

7. Нажмите Ctrl+Shift+Esc, чтобы открыть диспетчер задач.

8. Если диспетчер задач находится в режиме сокращенного вывода, щелкните на кнопке Подробнее (More Details).

9. Перейдите на вкладку Процессы (Processes).

10. Найдите приложение Windows Command Processor и раскройте узел. В нем должен появиться заголовок Parent, как на следующем снимке экрана:

1-14.tif 

11. Щелкните правой кнопкой мыши на строке Windows Command Processor и выберите команду Подробнее (Go To Details).

12. Щелкните правой кнопкой мыши на процессе cmd.exe и выберите команду Завершить дерево процессов (End Process Tree).

13. Щелкните на кнопке Завершить дерево процессов (End Process Tree) в диалоговом окне подтверждения.

Первое окно командной строки закрывается, но окно Paint остается, потому что оно было «внуком» закрытого окна командной строки. Так как непосредственный родитель Paint был завершен, между первым процессом и его «внуком» связи не осталось.

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

• Вывод маркера безопасности процесса (списки групп и привилегий, состояние виртуализации).

• Цветовое выделение для отображения изменений в списках процессов, потоков, DLL-библиотек и дескрипторов.

• Список служб в процессах-хостах служб, с выводимым именем и описанием.

• Список дополнительных атрибутов процессов (например, политики устранения рисков (mitigation) и уровни защиты процессов).

• Процессы, являющиеся частью заданий, и подробная информация о заданиях.

• Процессы-хосты приложений .NET и информация, относящаяся к .NET (например, список доменов приложений, загруженных сборок и счетчиков производительности CLR).

• Процессы, являющиеся хостами Windows Runtime.

• Время запуска процессов и потоков.

• Полный список файлов, отображенных в память (не только DLL).

• Возможность приостановки процесса или потока.

• Возможность уничтожения отдельных потоков.

• Простые средства идентификации процессов, создающих наибольшую нагрузку на процессор за период времени.

ПРИМЕЧАНИЕ Системный монитор может выводить информацию о загрузке процессора для заданного набора процессов, но не обеспечивает автоматического отображения процессов, созданных после начала сеанса. На это способна только ручная трассировка двоичных выходных данных.

Process Explorer также открывает централизованный удобный доступ к разно­образной информации:

• Дерево процессов с возможностью свертки частей дерева.

• Открытые дескрипторы в процессе, включая безымянные.

• Список DLL-библиотек (и файлов, отображенных в память).

• Активность потока в процессе.

• Стеки потоков пользовательского режима и режима ядра с информацией соответствия адресов и имен, полученной при помощи библиотеки Dbghelp.dll из инструментария отладки для Windows.

• Более точные данные загрузки процессора с использованием счетчика циклов потоков, формирующие более точную картину работы процессора (см. главу 4 «Потоки»).

• Уровни целостности.

• Подробная информация о распределении памяти: пиковое выделение памяти, лимиты выгружаемого и невыгружаемого пула памяти ядра (другие программы выводят только текущий размер).

Ниже описан вводный эксперимент с использованием Process Explorer.

Эксперимент: просмотр информации о процессах в Process Explorer

Загрузите последнюю версию Process Explorer на сайте Sysinternals и запустите ее. Программу можно запустить с привилегиями стандартного пользователя. Также возможен другой вариант: щелкните правой кнопкой мыши на исполняемом файле и выберите команду Запустить от имени администратора (Run As Administrator), чтобы выполнить ее с привилегиями администратора. В этом случае Process Explorer устанавливает драйвер, предоставляющий расширенные возможности. Следующее описание работает одинаково независимо от способа запуска Process Explorer.

При первом запуске Process Explorer следует настроить информацию символических имен. Если этого не сделать, при двойном щелчке на процессе и переходе на вкладку Threads вы получите сообщение о том, что символические имена не настроены. При правильной настройке Process Explorer — получить доступ к символической информации для вывода символического имени стартовой функции потока, а также имен функций из стека вызовов потока. Эта возможность поможет понять, что делает каждый поток в процессе. Чтобы получить доступ к символическим именам, следует установить средства отладки для Windows (см. далее в этой главе). Выберите команду Options401682.pngConfigure Symbols, введите путь к библиотеке Dbghelp.dll в папке Debugging Tools и действительный путь к символической информации. Например, в 64-разрядной системе следующая конфигурация будет верна, если средства отладки для Windows установлены в стандартной папке в составе WDK:

1-16.tif 

В приведенном примере используется сервер символической информации, а копия символических файлов хранится на локальной машине в папке C:\symbols. (При нехватке места вы можете заменить ее любой другой папкой, скажем, на другом диске.) За дополнительной информацией о настройке символических серверов обращайтесь по адресу .

СОВЕТ Символический сервер Microsoft можно настроить, присвоив переменной окружения _NT_SYMBOL_PATH значение, показанное на иллюстрации. Многие программы проверяют значение этой переменной автоматически — Process Explorer, отладчики, являющиеся частью средств отладки для Windows, Visual Studio и т.д. В этом случае вам не придется настраивать каждую программу по отдельности.

При запуске Process Explorer по умолчанию используется режим дерева процессов. Вы можете развернуть нижнюю панель, чтобы вывести списки открытых дескрипторов, DLL и файлов, отображенных в память. (Эта тема рассматривается в главе 5 «Управление памятью» и в главе 8 части 2.) Также выводится экранная подсказка с командной строкой и путем процесса; чтобы увидеть ее, наведите указатель мыши на имя процесса. Для некоторых типов процессов в подсказку также включаются дополнительные сведения:

службы в процессе-хосте служб (например, Svchost.exe);

задачи в процессе-хосте задач (например, TaskHostw.exe);

цель процесса Rundll32.exe, используемая для элементов Панели управления и другой функциональности;

информация класса COM при размещении в процессе Dllhost.exe (суррогат COM+ по умолчанию);

информация о поставщике для процессов-хостов WMI (Windows Management Instrumentation), таких как WMIPrvSE.exe (дополнительная информация о WMI приведена в главе 8 части 2);

информация пакета для процессов Windows Apps (процессы-хосты Windows Runtime; см. раздел «Windows Runtime» этой главы).

1-17.tif 

Некоторые основные возможности Process Explorer.

1. Обратите внимание: процессы, являющиеся хостами для служб, по умолчанию выделяются розовым цветом. Ваши собственные процессы выделены синим. Чтобы изменить цветовое выделение, откройте меню и выберите команду Options401877.pngConfigure Colors.

2. Наведите указатель мыши на имя образа процесса. На экране появляется подсказка с полным путем. Как упоминалось ранее, для некоторых типов процессов в подсказку включается дополнительная информация.

3. Выберите команду View401971.pngSelect Columns. На вкладке Process Image включите вывод пути образа (флажок Image Path).

4. Щелкните на заголовке столбца Process, чтобы отсортировать процессы. Обратите внимание: представление в виде дерева исчезает. (Вы можете либо вывести дерево, либо провести сортировку по любому из показанных столбцов.) Снова щелкните на заголовке столбца Process; вывод переключается на сортировку по убыванию (от Z к A). Третий щелчок возвращает список к режиму дерева.

5. Откройте меню View и снимите пометку команды Show Processes from All Users, чтобы в списке отображались только ваши процессы.

6. Откройте меню Options, выберите команду Difference Highlight Duration и введите новое значение: 3 секунды. Затем запустите новый процесс (любой). Обратите внимание: новый процесс выделяется зеленым цветом на 3 секунды. Завершите новый процесс; прежде чем исчезнуть из списка, он выделяется красным цветом на 3 секунды. Такое выделение может пригодиться для наблюдения за созданием и уничтожением процессов в вашей системе.

7. Дважды щелкните на процессе и исследуйте различные вкладки в списке свойств процесса. (Содержимое этих вкладок будет упоминаться в различных экспериментах в книге при объяснении выводимой на них информации.)

Потоки

Программный поток (или просто поток) — последовательность команд внутри процесса, планируемая Windows для исполнения. Без потоков программа процесса не сможет выполняться. Поток содержит следующие важнейшие компоненты:

• Содержимое набора регистров CPU, представляющих состояние процессора.

• Два стека: один для программного потока, который должен использоваться при выполнении в режиме ядра, другой — для выполнения в пользовательском режиме.

• Закрытая область памяти, называемая локальной памятью потока команд (TLS, Thread-Local Storage); используется подсистемами, библиотеками времени выполнения и динамическими библиотеками DLL.

• Уникальный идентификатор, называемый идентификатором потока (TID, Thread ID); является частью внутренней структуры идентификатора клиента (client ID). Идентификаторы процесса и потока генерируются из одного пространства имен, поэтому они никогда не перекрываются.

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

Регистры, стеки и закрытая область памяти называются контекстом потока. Так как эта информация зависит от архитектуры машины, на которой работает Windows, структура неизбежно привязывается к конкретной архитектуре. Функция Windows GetThreadContext предоставляет доступ к этой информации, зависящей от архитектуры (в виде блока CONTEXT).

Так как переключение выполнения между потоками требует участия планировщика ядра, эта операция может быть довольно затратной, особенно если два потока часто передают управление между собой. В Windows реализованы два механизма для сокращения этих затрат: волокна (fibers) и планирование пользовательского режима (UMS, User Mode Scheduling).

ПРИМЕЧАНИЕ Потоки 32-разрядного приложения, выполняемого в 64-разрядной версии Windows, будут содержать как 32-, так и 64-разрядные контексты, которые будут использоваться WoW64 (Windows on Windows 64) для переключения приложения из 32-разрядного режима в 64-разрядный при необходимости. Эти потоки будут иметь два стека пользовательского режима и два блока CONTEXT, а обычные функции Windows API будут возвращать 64-разрядный контекст. Впрочем, функция Wow64GetThreadContext будет возвращать 32-разрядный контекст. За дополнительной информацией о Wow64 обращайтесь к главе 8 части 2.

Волокна

Волокна позволяют приложению планировать свои потоки выполнения, а не полагаться на механизм приоритетного планирования, встроенный в Windows. Волокна также часто называют «облегченными потоками». В отношении планирования волокна невидимы для ядра, потому что они реализуются в пользовательском режиме в Kernel32.dll. Чтобы использовать волокна, следует сначала вызвать функцию Windows ConvertThreadToFiber. Эта функция преобразует поток в работающее волокно. В дальнейшем преобразованное волокно может создавать дополнительные волокна функцией CreateFiber. (Каждое волокно может иметь собственный набор волокон.) Однако, в отличие от потоков, волокно не начинает выполняться до того, как оно будет вручную выбрано вызовом функции SwitchToFiber. Новое волокно продолжает выполняться, пока не завершится или не вызовет SwitchToFiber с выбором другого волокна для выполнения. За дополнительной информацией обращайтесь к описанию функций волокон в документации Windows SDK.

ПРИМЕЧАНИЕ Использовать волокна обычно не рекомендуется, потому что они «невидимы» для ядра. Также волокна создают проблемы с совместным использованием локальной памяти потока (TLS), потому что несколько волокон могут выполняться в одном потоке. И хотя существует локальная память волокон (FLS, Fiber Local Storage), она не решает всех проблем совместного использования, а волокна, ориентированные на ввод/вывод, все равно работают плохо. Наконец, волокна не могут параллельно выполняться на нескольких процессорах и ограничиваются только кооперативной многозадачностью. Как правило, лучше доверить планирование ядру Windows и использовать для решения задач потоки.

Планирование пользовательского режима (UMS)

Потоки UMS (User Mode Scheduling), доступные только в 64-разрядных версиях Windows, предоставляют все основные преимущества волокон при минимуме их недостатков. Потоки UMS обладают собственным состоянием ядра, поэтому они «видимы» для ядра, что позволяет нескольким потокам UMS выдавать блокирующие системные вызовы, совместно использовать ресурсы и конкурировать за них. Или, когда двум и более потокам UMS требуется выполнить работу в пользовательском режиме, они могут периодически переключать контексты выполнения (уступая управление другому потоку) в пользовательском режиме, вместо того чтобы задействовать планировщик. С точки зрения ядра продолжает работать один поток, и ничего не изменилось. Когда поток UMS выполняет операцию, требующую входа в режим ядра (например, вызов системной функции), он переключается на специально выделенный поток режима ядра (так называемое «направленное переключение контекста»). И хотя параллельные потоки UMS также не могут выполняться на нескольких процессорах, они работают в условиях модели с вытеснением (pre-emptible), которая не является чисто кооперативной.

Хотя потоки обладают собственным контекстом выполнения, все потоки в процессе совместно используют виртуальное адресное пространство процесса (в дополнение к остальным ресурсам, принадлежащим процессу). Это означает, что все потоки в процессе обладают полным доступом для чтения/записи к виртуальному адресному пространству процесса. При этом потоки не могут случайно обратиться к адресному пространству другого процесса, если только другой процесс не откроет доступ к части своего закрытого адресного пространства в виде раздела общей памяти (в Windows API используется термин «объект сопоставления файла», file mapping object) или если один процесс не обладает правом открытия другого процесса с использованием межпроцессных функций памяти, таких как ReadProcessMemory и WriteProcessMemory (процесс, выполняемый с той же учетной записью и не работающий внутри контейнера приложения или другого типа изолированной среды, может получить их по умолчанию, если целевой процесс не установит защиту).

Помимо закрытого адресного пространства и одного или нескольких потоков, у каждого процесса имеется контекст безопасности и список открытых дескрипторов объектов ядра: файлов, разделов общей памяти, объектов синхронизации (мьютексы, события или семафоры) — рис. 1.2.

345588.png 

Рис. 1.2. Процесс и его ресурсы

Контент безопасности каждого процесса хранится в объекте, называемом маркером доступа (access token). Маркер доступа процесса содержит идентификационные данные безопасности и учетные данные процесса. По умолчанию потоки не имеют собственного маркера доступа, но могут получить его; это позволяет отдельным потокам олицетворять контент безопасности другого процесса (включая процессы в удаленной системе Windows), не затрагивая другие потоки в процессе. (За дополнительной информацией о процессах и безопасности потоков обращайтесь к главе 7.)

Дескрипторы виртуальных адресов (VAD, Virtual Address Descriptors) — структуры данных, используемые диспетчером памяти для отслеживания виртуальных адресов, используемых процессом. Эти структуры данных более подробно описаны в главе 5.

Задания

В Windows реализовано расширение модели процесса — так называемые задания. Главная функция объекта задания (job) — обеспечить возможность управления и выполнения операций с группами процессов как с единым целым. Объект задания позволяет управлять некоторыми атрибутами и устанавливает ограничения для процессов, связанных с заданием. Также он хранит основную учетную информацию для всех процессов, связанных с заданием, и для всех заданий, которые были связаны с заданием, но успели завершиться. В каком-то смысле объект задания компенсирует отсутствие структурированного дерева процессов в Windows — тем не менее во многих отношениях он мощнее дерева процессов в стиле UNIX.

ПРИМЕЧАНИЕ Process Explorer может выводить процессы, управляемые заданиями; обычно они обозначаются процессом, но по умолчанию эта возможность не включена (чтобы включить ее, откройте меню Options и выберите команду Configure Colors). Более того, страницы свойств таких процессов содержат дополнительную вкладку Job с информацией о самом объекте задания.

Внутренняя структура процессов и заданий подробнее описана в главе 3, а потоки и алгоритмы планирования потоков — в главе 4.

Виртуальная память

В Windows реализована система виртуальной памяти, основанная на модели плоского (линейного) адресного пространства, которая создает для каждого процесса иллюзию огромного закрытого адресного пространства. Виртуальная память формирует логическое представление памяти, которое может не соответствовать физической структуре. Во время выполнения диспетчер памяти — при поддержке оборудования — транслирует (отображает) виртуальные адреса в физические, где фактически хранятся данные. Управляя защитой и отображением адресов, ОС может предотвращать столкновения отдельных процессов или перезапись данных ОС.

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

Чтобы пользоваться преимуществами виртуальной памяти, приложения не нужно никак изменять — поддержка оборудования позволяет диспетчеру памяти делать все необходимое, при этом процессы и потоки ничего не знают о происходящем и никак не содействуют. На рис. 1.3 продемонстрировано использование виртуальной памяти двумя процессами; части памяти отображаются в физическую память (ОЗУ), а другие части выгружаются на диск. Обратите внимание на то, что непрерывные блоки виртуальной памяти могут отображаться в несмежные блоки физической памяти. Эти блоки называются страницами, а их размер по умолчанию составляет 4 Кбайт.

386399.png 

Рис. 1.3. Отображение виртуальной памяти в физическую

Размер виртуального адресного пространства изменяется в зависимости от аппаратной платформы. В 32-разрядных платформах x86 общее виртуальное адресное пространство ограничено теоретическим максимумом 4 Гбайт. По умолчанию Windows выделяет нижнюю половину адресного пространства (адреса от 0x80000000 до 0xFFFFFFFF) процессам для их собственной закрытой памяти, а верхнюю половину (адреса от 0x80000000 до 0xFFFFFFFF) — для собственного защищенного использования памяти ОС. Отображения нижней половины изменяются в соответствии с виртуальным адресным пространством текущего процесса, но отображения верхней половины (в большинстве) всегда состоят из виртуальной памяти ОС. Windows поддерживает параметры времени загрузки (например, квалификатор increaseuserva в базе данных Boot Configuration Database (см. главу 5)), которые предоставляют процессам, выполняющим особым образом помеченные программы, возможность использовать до 3 Гбайт закрытого адресного пространства, оставляя 1 Гбайт для ОС. (Под «особой пометкой» мы понимаем флаг обработки расширенного адресного пространства, установленный в заголовке исполняемого образа.) Этот параметр разрешает приложениям, таким как серверы баз данных, хранить большие объемы информации в адресном пространстве процесса, сокращая необходимость в отображении представлений базы данных на диске с повышением общей производительности (хотя в некоторых случаях потеря 1 Гбайт для системы может привести к более ярко выраженной потере производительности на общесистемном уровне). На рис. 1.4 изображены две типичные структуры виртуального адресного пространства, поддерживаемые 32-разрядными версиями Windows. (Параметр increaseuserva позволяет исполняемым образам с установленным флагом обработки расширенного адресного пространства использовать адреса от 2 до 3 Гбайт.)

345610.png 

Рис. 1.4. Типичная структура адресного пространства в 32-разрядных версиях Windows

Хотя три гигабайта лучше двух, этого все равно недостаточно для отображения в виртуальное адресное пространство очень больших (многогигабайтных) баз данных. Для решения этой проблемы в 32-разрядных системах Windows предоставляет механизм AWE (Address Windowing Extensions), позволяющий 32-разрядному приложению выделить до 64 Гбайт физической памяти, а затем отображать представления (или окна) в свое 2-гигабайтное виртуальное адресное пространство. И хотя использование AWE перекладывает бремя управления отображением виртуальной памяти в физическую память на разработчика, оно решает проблему с необходимостью прямого обращения к физической памяти большого объема, которая не может быть отображена в 32-разрядное адресное пространство процесса.

64-разрядные версии Windows предоставляют для процессов значительно большее адресное пространство: 128 Тбайт в Windows 8.1, Server 2012 R2 и более поздних системах. На рис. 1.5 изображено упрощенное представление структуры адресного пространства в 64-разрядных системах. (За подробным описанием обращайтесь к главе 5.) Учтите, что эти размеры не определяются архитектурными ограничениями таких платформ. 64 бита адресного пространства — это 2 в 64-й степени, или 16 Эбайт (1 Эбайт = 1024 Пбайт, или 1 048 576 Тбайт), но современное 64-разрядное оборудование ограничивает его меньшими значениями. Неотображаемая область на рис. 1.5 много больше возможной отображаемой области (приблизительно в 1 миллион раз больше в Windows 8), так что масштаб на изображениях не соблюдается (притом очень сильно).

Подробное описание реализации диспетчера памяти, включая преобразование адресов и управление физической памятью в Windows, приведено в главе 5.

386417.png 

Рис. 1.5. Типичная структура адресного пространства в 64-разрядных версиях Windows

Режим ядра и пользовательский режим

Чтобы пользовательские приложения не могли прочитать критические данные операционной системы и/или изменить их, в Windows предусмотрены два режима доступа к процессору (даже если процессор, на котором работает Windows, поддерживает более двух режимов): пользовательский режим (user mode) и режим ядра (kernel mode). Код пользовательских приложений выполняется в пользовательском режиме, а код ОС (системные службы, драйверы устройств и т.д.) работает только в режиме ядра. Режимом ядра называется режим работы процессора, в котором доступна вся системная память и все команды процессора. У одних процессоров для описания различий между режимами используется термин «уровень привилегий» или «кольцо», другие используют такие термины, как «режим супервизора» и «режим приложения». Независимо от названия низкоуровневое программное обеспечение операционной системы наделяется более высоким уровнем привилегий, чем процессы пользовательского режима, чтобы некорректное поведение приложения не могло нарушить стабильность системы в целом.

ПРИМЕЧАНИЕ Архитектуры процессоров x86 и x64 определяют четыре уровня привилегий (четыре кольца) для защиты системного кода и данных от случайной или злонамеренной перезаписи менее привилегированным кодом. Windows использует уровень привилегий 0 (кольцо 0) для режима ядра и уровень привилегий 3 (кольцо 3) для пользовательского режима. Причина, по которой Windows использует только два уровня, заключается в том, что в некоторых аппаратных архитектурах (ARM в наши дни, MIPS/Alpha в прошлом) реализуется только два уровня привилегий. Выбор минимального уровня, поддерживаемого всеми системами, позволяет реализовать более эффективную и портируемую архитектуру, особенно если учесть, что другие уровни колец x86/x64 не предоставляют таких же гарантий, как комбинация колец 0/3.

Хотя каждый процесс Windows обладает собственным закрытым адресным пространством, код ОС режима ядра и код драйверов устройств совместно используют единое виртуальное адресное пространство. Каждая страница виртуальной памяти снабжается метками, показывающими, в каком режиме доступа должен находиться процессор для выполнения чтения и/или записи в страницу. Страницы системного пространства доступны только из режима ядра, тогда как все страницы пользовательского адресного пространства доступны как из пользовательского режима, так и из режима ядра. Страницы, доступные только для чтения (например, страницы, содержащие статические данные), недоступны для записи из любого режима. Кроме того, на процессорах, поддерживающих защиту памяти с запретом исполнения, Windows помечает страницы с данными как неисполняемые, предотвращая случайное или злонамеренное исполнение кода в областях данных (при включенном механизме защиты DEP (Data Execution Prevension)).

Windows не предоставляет никакой защиты при использовании закрытой системной памяти, доступной для чтения/записи, компонентами, работающими в режиме ядра. Иначе говоря, в режиме ядра код ОС и драйверов устройств обладает полным доступом к памяти системного пространства и может обойти механизмы безопасности Windows при обращении к объектам. Так как основная часть кода ОС Windows работает в режиме ядра, очень важно, чтобы компоненты, работающие в режиме ядра, были тщательно спроектированы и протестированы. Это необходимо для предотвращения возможных нарушений системной безопасности или подрыва стабильности системы.

Отсутствие защиты также показывает, насколько важно сохранять бдительность при загрузке сторонних драйверов устройств — особенно неподписанных, потому что в режиме ядра драйвер обладает полным доступом ко всем данным ОС. Именно по этой причине в Windows 2000 появился механизм цифровой подписи драйверов. Он предупреждает пользователя о попытке добавления неподписанного драйвера Plug-and-Play (или при соответствующей настройке блокирует такие попытки), но не влияет на другие типы драйверов. За дополнительной информацией о цифровой подписи драйверов обращайтесь к главе 6 «Подсистема ввода/вывода». Кроме того, механизм Driver Verifier помогает разработчикам драйверов устройств находить ошибки (такие, как переполнение буфера или утечка памяти), способные вызвать проблемы безопасности или надежности. (Механизм Driver Verifier также рассматривается в главе 6.)

В 64-разрядных и ARM-версиях Windows 8.1 политика подписывания кода режима ядра (KMCS, Kernel-Mode Code-Signing) требует, чтобы все драйверы устройств (а не только драйверы Plug-and-Play) подписывались с криптографическим ключом, выданным одним из ведущих центров сертификации. Пользователь не может выполнить принудительную установку неподписанного драйвера, даже с правами администратора. Тем не менее в качестве разового исключения это ограничение можно отключить вручную. В этом случае драйверы самоподписываются, на обоях рабочего стола выводится надпись «Тестовый режим», а некоторые функции управления цифровыми правами DRM (Digital Rights Management) отключаются.

В Windows 10 компания Microsoft реализовала еще более значительное изменение, которое было введено через год после выхода системы в составе июльского обновления Anniversary Update (версия 1607). В то время все новые драйверы Windows 10 должны были подписываться только двумя возможными центрами сертификации с сертификатом SHA-2 Extended Validation (EV) вместо обычного файлового сертификата SHA-1 и его 20 центрами сертификации. После снабжения подписью EV драйвер оборудования должен был отправляться в Microsoft через портал SysDev (System Device) для аттестации, после которой драйвер получал цифровую подпись Microsoft. Соответственно, ядро принимало только драйверы Windows 10 с подписью Microsoft без каких-либо исключений, кроме упомянутого выше тестового режима. Драйверы, подписанные до выхода Windows 10 (июль 2015 года), на тот момент продолжали загружаться с обычной подписью.

В Windows Server 2016 операционная система действует еще радикальнее. Кроме упоминавшихся требований EV простого аттестационного подписывания недостаточно. Чтобы драйвер Windows 10 загружался в серверной системе, он должен пройти жесткий процесс сертификации WHQL (Windows Hardware Quality Labs) в составе HCK (Hardware Compatibility Kit) и пройти формальную оценку. Только драйверам с подписью WHQL — предоставляющим системным администраторам определенные гарантии совместимости, безопасности, производительности и стабильности — разрешалась загрузка в таких системах. В целом сокращение количества сторонних драйверов, которым разрешалась загрузка в режиме ядра, значительно повысило стабильность и безопасность систем.

В версиях Windows некоторых производителей оборудования, платформ и даже в корпоративных конфигурациях любые из этих политик подписывания могут быть настроены, например, с использованием технологии Device Guard, которая будет кратко описана далее в разделе «Гипервизор» и в главе 7. По этой причине корпоративная версия может требовать подписей WHQL даже в клиентских системах Windows 10 или же запросить ослабление этого требования в системе Windows Server 2016.

Как будет показано в главе 2 «Архитектура системы», пользовательские приложения переключаются из пользовательского режима в режим ядра при вызове системных функций. Например, функция Windows ReadFile в конечном итоге должна вызвать внутреннюю функцию Windows, которая выполняет непосредственное чтение данных из файла. Поскольку эта функция обращается к внутренним системным структурам данных, она должна работать в режиме ядра. Специальная команда процессора инициирует переключение из пользовательского режима в режим ядра и заставляет процессор войти в код диспетчеризации системных вызовов в ядре. В свою очередь, этот код вызывает соответствующую внутреннюю функцию: Ntoskrnl.exe или Win32k.sys. Перед возвращением управления пользовательскому потоку процессор снова переключается в пользовательский режим. Таким образом ОС защищает себя и свои данные от анализа и модификации со стороны пользовательских процессов.

ПРИМЕЧАНИЕ Переключение из пользовательского режима в режим ядра (и обратно) не влияет на планирование потоков как таковое. Переключение режима не является переключением контекста. Дополнительная информация о диспетчеризации системных вызовов приведена в главе 2.

Таким образом, для пользовательского потока нормально проводить часть времени в пользовательском режиме и часть времени в режиме ядра. Более того, поскольку большая часть графической и оконной системы также выполняется в режиме ядра, процессы приложений, интенсивно работающих с графикой, могут проводить в режиме ядра больше времени, чем в пользовательском режиме. Чтобы убедиться в этом, запустите какое-нибудь графическое приложение (например, Microsoft Paint) и понаблюдайте за распределением времени между пользовательским режимом и режимом ядра при помощи одного из счетчиков производительности из табл. 1.3.

Более современные приложения могут использовать новые технологии (например, Direct2D и DirectComposition), которые выполняют большие объемы вычислений в пользовательском режиме и передают ядру только низкоуровневые данные поверхностей. Таким образом сокращается время, расходуемое на переключение между пользовательским режимом и режимом ядра.

Таблица 1.3. Счетчики производительности, относящиеся к режиму процессора

Объект: счетчик

Функция

Процессор: % работы в привилегированном режиме (Processor: % Privileged Time)

Процент времени, проводимого конкретным процессором (или всеми процессорами) в режиме ядра, за заданный промежуток времени

Процессор: % работы в пользовательском режиме (Processor: % User Time)

Процент времени, проводимого конкретным процессором (или всеми процессорами) в пользовательском режиме, за заданный промежуток времени

Процесс: % работы в привилегированном режиме (Process: % Privileged Time)

Процент времени, проводимого потоками процесса в режиме ядра, за заданный промежуток времени

Процесс: % работы в пользовательском режиме (Process: % User Time)

Процент времени, проводимого потоками процесса в пользовательском режиме, за заданный промежуток времени

Поток: % работы в привилегированном режиме (Thread: % Privileged Time)

Процент времени, проводимого потоком в режиме ядра, за заданный промежуток времени

Поток: % работы в пользовательском режиме (Thread: % User Time)

Процент времени, проводимого потоком в пользовательском режиме, за заданный промежуток времени

Эксперимент: режим ядра и пользовательский режим

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

1. Откройте меню Пуск (Start) и введите команду Run Performance Monitor (коман­да должна быть заполнена автоматически еще до того, как вы закончите ее вводить), чтобы запустить Системный монитор.

2. Выберите узел Системный монитор (Performance Monitor) в категории Средства наблюдения (Performance/Monitoring Tools) в дереве на левой панели.

3. Чтобы удалить счетчик по умолчанию, отображающий общее время процессора, щелкните на кнопке Удалить (Delete) на панели инструментов или нажмите клавишу Delete на клавиатуре.

4. Щелкните на кнопке Добавить (Add) (+) на панели инструментов.

5. Разверните категорию Процессор (Processor), щелкните на счетчике % работы в привилегированном режиме (% Privileged Time) и, удерживая клавишу Ctrl, щелкните на счетчике % работы в пользовательском режиме (% User Time).

6. Щелкните на кнопке Добавить (Add), затем щелкните на кнопке OK.

7. Откройте окно командной строки и введите команду dir \\%computername%\c$/s, чтобы просканировать структуру каталогов на диске C.

1-26.tif 

8. По окончании работы закройте программу.

Эту информацию также можно быстро получить в диспетчере задач. Перейдите на вкладку Быстродействие (Performance), щелкните правой кнопкой мыши на графике загрузки процессора и выберите команду Вывод времени ядра (Show Kernel Times). На графике загрузки процессора время, проводимое в режиме ядра, будет отображаться более темным оттенком синего.

Чтобы увидеть, как сам Системный монитор использует данные о времени, проводимом в режиме ядра и пользовательском режиме, добавьте счетчики времени режима ядра и пользовательского режима для каждого процесса в системе.

1. Если Системный монитор был закрыт, снова запустите его. (Если он уже работает, сбросьте отображаемую информацию; для этого щелкните правой кнопкой мыши на области графика и выберите команду Удалить все счетчики (Remove All Counters).)

2. Щелкните на кнопке Добавить (Add) на панели инструментов.

3. В области доступных счетчиков раскройте категорию Процесс (Process).

4. Выберите счетчики % работы в привилегированном режиме (% Privileged Time) и % работы в пользовательском режиме (% User Time).

5. Выберите несколько процессов в поле Экземпляр (Instance) (например, mmc, csrss и Idle).

6. Щелкните на кнопке Добавить (Add), затем щелкните на кнопке OK.

7. Быстро переместите указатель мыши по экрану.

8. Нажмите клавиши Ctrl+H, чтобы включить режим цветового выделения. Текущий выбранный счетчик выделяется черным цветом.

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

При перемещении мыши вы увидите, что в столбце Экземпляр (Instance) процесса mmc Системного монитора возрастает время как в режиме ядра, так и в пользовательском режиме. Это связано с тем, что процесс выполняет код приложения в пользовательском режиме и вызывает функции Windows, выполняемые в режиме ядра. Также при перемещении мыши можно заметить активность потока режима ядра в процессе с именем csrss. Эта активность обусловлена тем, что к этому процессу присоединен поток низкоуровневого ввода режима ядра подсистемы Windows, обеспечивающий ввод данных с клавиатуры и мыши. (За дополнительной информацией о системных потоках и подсистемах обращайтесь к главе 2.) Наконец, процесс Idle, который проводит почти 100 % времени в режиме ядра, процессом вообще не является — это псевдопроцесс, используемый для учета простоя процессорного времени. Как можно заметить по режиму, в котором выполняются потоки процесса Idle, когда системе Windows нечем заняться, она занимается этим в режиме ядра.

Гипервизор

Последние достижения в сфере приложений и программного обеспечения, такие как появление облачных сервисов и повсеместное распространение устройств IoT, привели к тому, что операционным системам и производителям оборудования приходится искать более эффективные способы виртуализации других «гостей» ОС на оборудовании машины, будь то размещение многочисленных обитателей фермы серверов и работа ста изолированных веб-сайтов на одном сервере или же возможность тестирования разработчиками десятков разновидностей ОС без покупки специализированного оборудования. Потребность в быстрой, эффективной и безопасной виртуализации породила новые модели вычислений и подходов к проектированию программных продуктов. В наши дни некоторые программы работают в контейнерах, которые обеспечивают полную изоляцию виртуальных машин, предназначенных исключительно для выполнения одного стека приложений или инфраструктуры (в качестве примера можно привести технологию Docker, поддерживаемую в Windows 10 и Server 2016); таким образом, границы между управляющей системой и гостями поднимаются на новый уровень.

Для предоставления сервиса виртуализации почти все современные решения пользуются услугами гипервизора — специализированного, высокопривилегированного компонента, который обеспечивает виртуализацию и изоляцию всех ресурсов машины, от виртуальной и физической памяти до прерываний устройств и даже устройств с интерфейсами PCI и USB. Например, в основе функциональности клиента Hyper-V, предоставляемой в Windows 8.1 и выше, лежит гипервизор Hyper-V. Все конкурирующие продукты — Xen, KVM, VMware и VirtualBox — реализуют собственные гипервизоры, каждый из которых обладает своими достоинствами и недостатками.

Из-за своей привилегированной природы и из-за уровня доступа даже большего, чем у самого ядра, гипервизор имеет очевидное преимущество перед гостевыми экземплярами других операционных систем: он может обеспечивать защиту и сбор управляющей информации одного экземпляра хоста для предоставления гарантий, превышающих возможности ядра. В Windows 10 компания Microsoft использует гипервизор Hyper-V для предоставления нового набора сервисов виртуализационной безопасности VBS (Virtualization-Based Security):

• Device Guard предоставляет сервис HVCI (Hypervisor Code Integrity) для усиления гарантий подписывания кода по сравнению с KMCS и обеспечивает возможность настройки политики подписывания в ОС Windows как для кода пользовательского режима, так и для кода режима ядра.

• Hyper Guard защищает ключевые структуры данных и код, относящиеся к режиму ядра и гипервизору.

• Credential Guard предотвращает несанкционированный доступ к учетным данным и секретам учетной записи домена в сочетании с безопасной биометрией.

• Application Guard — еще более сильная изоляция для браузера Microsoft Edge.

• Host Guardian и Shielded Fabric используют виртуальный модуль TPM (v-TPM) для защиты виртуальной машины от инфраструктуры, на которой она работает.

Кроме того, гипервизор Hyper-V обеспечивает некоторые ключевые меры защиты ядра от эксплойтов и других видов атак. Главное преимущество всех этих технологий заключается в том, что в отличие от предыдущих средств безопасности на базе ядра они неуязвимы для плохо написанных или вредоносных драйверов независимо от того, подписаны они или нет. Тем самым обеспечивается их высокая устойчивость перед опытными злоумышленниками наших дней. Все это стало возможным благодаря реализации в гипервизоре виртуальных уровней доверия VTL (Virtual Trust Level). Так как обычная операционная система и ее компоненты работают в менее привилегированном режиме (VTL 0), а эти технологии VBS работают в режиме VTL 1 (более высокий уровень привилегий), они неуязвимы даже для кода режима ядра. Код как таковой остается в пространстве привилегий VTL 0. Таким образом, уровни VTL можно рассматривать как ортогональные по отношению к уровням привилегий процессора: режим ядра и пользовательский режим существуют внутри каждого уровня VTL, но гипервизор управляет привилегиями между VTL. В главе 2 приведена дополнительная информация об архитектуре, использующей супервизор, а в главе 7 эти механизмы безопасности VBS рассматриваются более подробно.

Микропрограммы

Компоненты Windows все сильнее зависят от безопасности операционной системы и ее ядра, а ядро сейчас зависит от защиты гипервизора. Возникает вопрос: что может гарантировать, что эти компоненты были загружены корректно, и что может проверить их содержимое? Обычно этим занимается загрузчик (boot loader), но и ему необходим тот же уровень проверки подлинности, что создает еще более сложную иерархию доверия.

Что же должно стать фундаментом для цепочки доверия, гарантирующим нормальный процесс загрузки? В современной Windows 8 и более поздних системах эта роль отводится системной микропрограмме (firmware), которая в сертифицированных системах должна базироваться на спецификации UEFI. Как часть стандарта UEFI, предписываемого Windows (UEFI 2.3.1b; см. ), должна присутствовать безопасная реализация загрузки с сильными гарантиями и требованиями к качеству сертификации программного обеспечения, относящегося к загрузке.

Процесс проверки подлинности гарантирует безопасную загрузку компонентов Windows с самого начала процесса загрузки. Кроме того, такие технологии, как TPM (Trusted Platform Module), могут получать метрики процесса для предоставления аттестации (как локальной, так и удаленной). На основе партнерских отношений в отрасли Microsoft ведет белый и черный списки компонентов безопасной загрузки UEFI на случай ошибок или взлома загрузочного ПО, а обновления Windows также включают обновления микропрограмм.

Хотя тема микропрограммного ПО не будет рассматриваться до главы 11 «Запуск и завершение работы» в части 2, важно подчеркнуть его значимость в современной архитектуре Windows и значимость тех гарантий, которые оно должно предоставлять.

Службы терминалов и сеансы

Под термином «службы терминалов» (Terminal Services) в Windows понимается поддержка множественных интерактивных сеансов пользователя в одной системе. Благодаря службам терминалов Windows удаленный пользователь может создать сеанс на другой машине, выполнить вход и запустить приложения на сервере. Сервер передает графический интерфейс (GUI) клиенту (а также другие настраиваемые ресурсы, такие как буфер обмена и звук), а клиент передает ввод пользователя обратно на сервер. (По аналогии с X Window System, Windows позволяет запускать приложения в серверной системе с передачей клиенту изображения вместо передачи всего рабочего стола.)

Исходный сеанс считается служебным (или нулевым) сеансом и содержит процессы-хосты системных служб (см. главу 9 части 2). Первый сеанс входа на физической консоли машины считается сеансом 1, а дополнительные сеансы создаются программой подключения к удаленному рабочему столу (Mstsc.exe) или через механизм быстрого переключения пользователей.

Клиентские выпуски Windows допускают подключение к машине одного удаленного пользователя, но если кто-то войдет с консоли, рабочая станция блокируется. Иначе говоря, система может использоваться либо в локальном, либо в удаленном режиме, но не одновременно и в том и в другом. Выпуски Windows, включающие Windows Media Center, допускают один интерактивный сеанс и до четырех сеансов Windows Media Center Extender.

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

Все клиентские выпуски Windows поддерживают множественные сеансы, которые создаются локально с помощью функции быстрого переключения пользователей; в любой момент времени используется только один из этих сеансов. Когда пользователь решает отключить свой сеанс вместо выполнения выхода из системы (например, если он щелкнет на кнопке Пуск (Start), выберет текущего пользователя и выберет в открывшемся подменю команду Сменить учетную запись (Switch Account) или нажмет Win+L и щелкнет на другом пользователе в левом нижнем углу экрана), текущий сеанс — т.е. процессы, выполняемые в этом сеансе, и все общесистемные структуры данных, описывающие сеанс, — остается активным в системе, а система возвращается к основному экрану входа (если она еще не находится на этом экране). При входе нового пользователя создается новый сеанс.

Для приложений, которые пожелают получить информацию о выполнении в сеансе сервера терминалов, существует набор Windows API для программного обнаружения и управления различными аспектами служб терминалов. (За подробностями обращайтесь к Windows SDK и документации Remote Desktop Services API.)

В главе 2 кратко описан процесс создания сеансов и эксперименты по просмотру информации сеансов в разных средствах, включая отладчик ядра. В разделе «Диспетчер объектов» главы 8 части 2 описано, как системное пространство имен объектов создается на уровне сеанса и как приложениям, которым нужно знать о других своих экземплярах в той же системе, получить эту информацию. Наконец, в главе 5 рассказано о том, как диспетчер памяти создает данные уровня сеанса и управляет ими.

Объекты и дескрипторы

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

Атрибутом объекта называется поле данных объекта, определяющее часть состояния объекта. Например, объект типа «процесс» содержит атрибуты, определяющие идентификатор процесса, базовый приоритет планирования и указатель на объект маркера доступа. Методы объектов — средства для выполнения операций с объектами — обычно читают или изменяют атрибуты объектов. Так, метод открытия процесса на входе получает идентификатор процесса, а на выходе возвращает указатель на объект.

ПРИМЕЧАНИЕ При создании объекта с использованием API диспетчера объектов ядра вызывающая сторона передает параметр с именем ObjectAttributes. Не путайте этот параметр с более общим смыслом атрибута, используемым в книге.

Самое принципиальное различие между объектом и обычной структурой данных — непрозрачность внутренней структуры объекта. Чтобы прочитать данные или записать их в объект, необходимо вызвать соответствующую сервисную функцию. Вы не можете напрямую прочитать данные или изменить их в объекте. Это различие отделяет реализацию объекта от кода, который просто использует этот объект — этот принцип позволяет легко менять реализации объекта с течением времени.

Объекты при содействии компонента ядра, называемого диспетчером объектов, предоставляют удобные средства для решения четырех важных задач ОС.

• Назначение удобочитаемых имен для системных ресурсов.

• Организация совместного использования ресурсов и данных между процессами.

• Защита ресурсов от несанкционированного доступа.

• Отслеживание ссылок, благодаря чему система понимает, когда объект больше не используется (и может быть автоматически удален из памяти).

Не все структуры данных в ОС Windows являются объектами. В объектах размещаются только те данные, к которым необходимо предоставить совместный доступ, которые нужно защитить, которым нужно назначить имя или которые нужно сделать видимыми для программ пользовательского режима (через системные вызовы). Структуры, используемые только одним компонентом ОС для реализации внутренних функций, объектами не являются. Объекты и дескрипторы (ссылки на объекты) более подробно рассматриваются в главе 8 части 2.

Безопасность

Система Windows изначально разрабатывалась с расчетом на безопасность и выполнение требований различных формальных правительственных и отраслевых спецификаций безопасности, таких как спецификация CCITSE (Common Criteria for Information Technology). Получение рейтинга безопасности, одобренного правительством, дает возможность ОС конкурировать в этой области. Конечно, многие из реализованных возможностей полезны в любой многопользовательской системе.

В состав базовых средств безопасности Windows входят:

• защита на уровне пользователей (дискреционная, т.е. предоставляемая на усмотрение) и обязательная защита для всех совместно используемых системных объектов: файлов, каталогов, процессов, потоков и т.д.;

• система аудита безопасности для учета субъектов (пользователей) и выполняемых ими действий;

• проверка пользователя при входе;

• предотвращение доступа со стороны пользователя к неинициализированным ресурсам (например, свободной памяти или дисковому пространству), освобожденным другим пользователем.

В Windows существует три формы управления доступом к объектам.

• Управление доступом на уровне пользователей (дискреционное управление доступом). Именно этот механизм защиты большинство людей представляют себе, когда речь заходит о безопасности ОС. С помощью этого механизма владельцы объектов (например, файлов или принтеров) предоставляют или блокируют доступ другим сторонам. При входе пользователю предоставляется набор учетных данных безопасности, или контекст безопасности. При попытке обращения к объекту контекст безопасности пользователя сравнивается со списком управления доступом того объекта, к которому он обращается. Результат сравнения определяет, разрешается ли выполнение запрашиваемой операции. В Windows Server 2012 и Windows 8 эта форма управления доступом усовершенствована реализацией управления доступом на базе атрибутов (DAC, Dynamic Access Control). Однако в списках управления доступом ресурсов не обязательно перечисляются конкретные пользователи и группы. Вместо этого в них указываются необходимые атрибуты, или утверждения (claims), для предоставления доступа к ресурсу: например, «Уровень допуска: Совершенно секретно» или «Стаж: 10 лет». Благодаря возможности автоматического заполнения таких атрибутов посредством разбора баз данных и схем SQL через Active Directory, эта существенно более элегантная и гибкая модель безопасности помогает организациям избежать неудобного ручного управления группами и иерархиями групп.

• Привилегированное управление доступом. Этот механизм необходим, когда механизма управления доступом на уровне пользователей недостаточно. Он гарантирует, что к защищенным объектам можно будет получить доступ даже в том случае, если их владелец недоступен. Например, если работник уволился из компании, администратор должен как-то получить доступ к файлам, которые были доступны только для этого работника. В таком случае в системе Windows администратор может назначить себя владельцем файла, чтобы управлять правами так, как потребуется.

• Контроль целостности учетных данных (MIC). Этот механизм используется, когда необходим дополнительный уровень контроля безопасности для защиты объектов, обращение к которым производится из той же учетной записи пользователя. Он используется для разных целей, от технологии частичной изоляции для приложений Windows Apps (см. далее) и изоляции защищенного режима Internet Explorer (и других браузеров) от конфигурации пользователя, до защиты объектов, созданных учетной записью администратора с повышенными правами, от обращений со стороны учетной записи администратора без повышенных прав. (За дополнительной информацией о механизме контроля учетных записей обращайтесь к главе 7.)

Начиная с Windows 8, для размещения приложений Windows Apps используется изолированная среда («песочница»), которая называется контейнером приложения (AppContainer). Она предоставляет изоляцию от других контейнеров приложений и процессов, не относящихся к приложениям Windows Apps. Код контейнеров приложений может взаимодействовать с брокерами (неизолированными процессами, работающими с учетными данными пользователя), а иногда с другими контейнерами приложений или процессами через четко определенные контракты, предоставляемые Windows Runtime. Классический пример — браузер Microsoft Edge, который выполняется в контейнере приложения и таким образом предоставляет улучшенную защиту от выполняемого внутри него вредоносного кода. Кроме того, сторонние разработчики могут использовать контейнеры приложений для аналогичной изоляции собственных приложений, не являющихся приложениями Windows Apps. Модель контейнера приложения вынуждает к значительному сдвигу традиционных парадигм программирования и переходу от традиционной реализации в форме многопоточного однопроцессного приложения к многопроцессной реализации.

Безопасность задействована во всех аспектах Windows API. Подсистема Windows реализует объектную безопасность по тому же принципу, что и ОС: общие объекты Windows защищаются от несанкционированного доступа за счет назначения им дескрипторов безопасности Windows. Когда приложение в первый раз пытается обратиться к общему объекту, подсистема Windows проверяет, обладает ли оно необходимыми правами. Если проверка безопасности проходит успешно, то подсистема Windows разрешает приложению продолжение операции.

Система безопасности Windows подробно рассматривается в главе 7.

Реестр

Если вы работаете с операционными системами Windows, вероятно, вы уже слышали о системном реестре или заглядывали в него. Трудно говорить о внутреннем устройстве Windows без упоминания реестра — системной базы данных с информацией, необходимой для загрузки и настройки конфигурации системы, общесистемными параметрами, управляющими работой Windows, базой данных безопасности и текущими настройками (например, используемой экранной заставкой). Кроме того, реестр открывает доступ к хранящимся в памяти временным данным, таким как текущее состояние оборудования системы (какие драйверы устройств загружены, какие ресурсы они используют и т.д.), а также счетчикам производительности Windows. Для обращения к счетчикам производительности, которые на самом деле в реестре не хранятся, используются функции реестра (хотя существует новый улучшенный API для обращения к счетчикам безопасности). За дополнительной информацией об обращениях к данным счетчиков производительности обращайтесь к главе 9 части 2.

Многим пользователям и администраторам Windows никогда не приходится обращаться к реестру напрямую (потому что для просмотра и изменения многих параметров конфигурации можно использовать стандартные административные программы). Реестр остается полезным источником внутренней информации Windows, потому что в нем содержатся многие настройки, влияющие на быстродействие и поведение системы. В книге часто упоминаются разные разделы реестра, относящиеся к рассматриваемому компоненту. Большинство разделов реестра, упоминаемых в книге, относится к кусту общесистемной конфигурации HKEY_LOCAL_MACHINE, который в дальнейшем будет обозначаться сокращением HKLM.

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

За дополнительной информацией о реестре и его внутренней структуре обращайтесь к главе 9 части 2.

Юникод

Windows отличается от большинства других операционных систем тем, что многие внутренние текстовые строки хранятся и обрабатываются в виде 16-разрядных символов Юникода (формально UTF-16LE; там, где в книге упоминается Юникод, имеется в виду UTF-16LE, если только в тексте прямо не указано иное). Юникод — стандарт международной кодировки символов, в котором определяются уникальные значения для большинства известных мировых кодировок и поддерживаются 8-, 16- и даже 32-разрядные кодировки для разных символов.

Так как многие приложения работают со строками 8-разрядных (однобайтовых) символов ANSI, многие функции Windows, получающие строковые параметры, имеют две точки входа: для Юникода (широкая, 16-разрядная) и для ANSI (узкая, 8-разрядная). Вызов узкой версии функции Windows сопровождается небольшой потерей производительности, так как входные строковые параметры преобразуются в Юникод перед обработкой системой, а выходные параметры преобразуются из Юникода в ANSI перед возвращением приложению. Таким образом, если у вас имеется старая служба или фрагмент кода, который должен выполняться в Windows, но этот код написан с использованием текстовых строк ANSI, Windows преобразует символы ANSI в Юникод для своего использования. Однако Windows никогда не преобразует данные, хранящиеся в файлах, — приложение само решает, где должны храниться данные храниться, в Юникоде или в ANSI.

Независимо от языка, все версии Windows содержат одни и те же функции. Вместо отдельных версий для разных языков Windows содержит единый двоичный код, чтобы одна установка могла поддерживать много языков (посредством добавления разных языковых пакетов). Приложения также могут пользоваться функциями Windows, что позволяет включать в приложение универсальные двоичные файлы, способные поддерживать разные языки.

ПРИМЕЧАНИЕ В старых операционных системах 9x не было встроенной поддержки Юникода. Это стало еще одной причиной для создания двух функций (для ASNI и Юникода). Например, функция Windows API CreateFile функцией вообще не является; это макрос, который расширяется в одну из двух функций: CreateFileA (ANSI) или CreateFileW (для Юникода; W означает «wide», т.е. «широкий»). Расширение выполняется на основании константы компиляции с именем UNICODE. Эта константа определяется по умолчанию в проектах Visual Studio C++, потому что работа с функциями Юникода предпочтительна. Впрочем, вместо макроса можно использовать низкоуровневое имя функции.

Следующий эксперимент демонстрирует эти пары функций.

Эксперимент: просмотр экспортируемых функций

В этом эксперименте мы воспользуемся программой Dependency Walker для просмотра функций, экспортируемых DLL-библиотекой подсистемы Win­dows.

1. Загрузите Dependency Walker по адресу . Если вы работаете в 32-разрядной системе, загрузите 32-разрядную версию Download Dependency. Для 64-разрядной системы загружается 64-разрядная версия. Распакуйте загруженный ZIP-файл в папку по своему выбору.

2. Запустите программу (depends.exe). Откройте меню File, выберите команду Open, перейдите в папку C:\Windows\System32 (предполагается, что система Windows установлена на диске C), найдите файл kernel32.dll и щелкните на кнопке Open.

3. Dependency Walker может выдать диалоговое окно с предупреждением. Не обращайте на него внимания и закройте окно.

4. Вы увидите несколько панелей с вертикальными и горизонтальными линиями разделения. Убедитесь в том, что в дереве вверху слева выбран файл kernel32.dll.

5. Взгляните на вторую панель вверху на правой стороне. На ней выводится список функций, экспортируемых из файла kernel32.dll. Щелкните на заголовке списка Function, чтобы отсортировать его по имени. Найдите функцию CreateFileA. Чуть ниже в списке находится и функция CreateFileW.

1-34.tif 

6. Как видите, многие функции, получающие хотя бы один строковый аргумент, в действительности существуют в двух версиях. На иллюстрации видны следующие функции: CreateFileMappingA/W, CreateFileTransactedA/W и CreateFileMappingNumaA/W.

7. Прокрутите список и найдите в нем другие функции. Вы также можете открыть другие системные файлы, такие как user32.dll и advapi32.dll.

Дополнительная информация о Юникоде доступна по адресу и в документации по программированию из библиотеки MSDN.

ПРИМЕЧАНИЕ В API на базе COM в системе Windows обычно используются строки Юникода, иногда обозначаемые типом BSTR. По сути это массив символов Юникода, завершенный нуль-символом; за 4 байта до начала массива символов в памяти хранится длина строки в байтах. В Windows Runtime API используются только строки Юникода, обозначаемые типом HSTRING — неизменяемым массивом символов Юникода.

Изучение внутреннего устройства Windows

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

Чтобы разжечь вас интерес к исследованию внутреннего устройства Windows, мы включили в книгу врезки «Эксперимент» с описанием конкретных аспектов внутреннего поведения Windows. (Несколько таких врезок уже встречалось вам ранее.) Мы рекомендуем самостоятельно повторить эксперименты, чтобы вы могли понаблюдать в действии многие аспекты, описанные в книге.

В табл. 1.4 перечислены основные средства, представленные в книге, с информацией об их происхождении.

Таблица 1.4. Средства для просмотра информации о внутреннем устройстве Windows

Средство

Имя образа

Происхождение

Startup Programs Viewer

AUTORUNS

Sysinternals

Access Check

ACCESSCHK

Sysinternals

Dependency Walker

DEPENDS

Global Flags

GFLAGS

Debugging Tools

Handle Viewer

HANDLE

Sysinternals

Отладчики ядра

WINDBG, KD

WDK, Windows SDK

Object Viewer

WINOBJ

Sysinternals

Системный монитор

PERFMON.MSC

Встроенная программа Windows

Pool Monitor

POOLMON

WDK

Process Explorer

PROCEXP

Sysinternals

Process Monitor

PROCMON

Systinternals

Task (Process) List

TLIST

Средства отладки

Диспетчер задач

TASKMGR

Встроенная программа Windows

Системный монитор и Монитор ресурсов

В этой книге мы часто возвращаемся к Системному монитору (который запускается из папки Администрирование (Administrative Tools) панели управления или командой perfmon в диалоговом окне запуска программы). А если говорить конкретнее, мы сосредоточимся на Системном мониторе и Мониторе ресурсов.

ПРИМЕЧАНИЕ Системный монитор решает три задачи: сбор информации о системе, просмотр журналов счетчиков производительности и установка сигналов (с использованием наборов сборщиков данных, которые также содержат журналы счетчиков производительности, данные трассировки и конфигурации). Для простоты при упоминании Системного монитора мы будем иметь в виду функцию сбора информации о системе.

Системный монитор предоставляет больше информации о том, как работает ваша система, чем любая другая программа. Он включает сотни базовых и расширенных счетчиков для разных объектов. Для каждой основной темы, описанной в книге, приводится таблица соответствующих счетчиков производительности. Счетчик производительности содержит краткие описания всех счетчиков. Чтобы просмотреть описания, выберите счетчик в окне Добавить счетчики (Add Counters) и установите флажок Отображать описание (Show Description).

И хотя всю низкоуровневую информацию о системе можно получить в Системном мониторе, Windows также включает программу Монитор ресурсов (запускается из меню Пуск (Start) или с вкладки Быстродействие (Performance) диспетчера задач), отображающую состояние четырех основных системных ресурсов: процессора, диска, сети и памяти. В базовом состоянии эти ресурсы отображаются с тем же уровнем информации, что и в диспетчере задач. Впрочем, они также содержат разделы, которые можно развернуть для получения дополнительной информации. Типичное окно Монитора ресурсов показано на с. 64.

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

Как и в Process Explorer, при выборе процесса (щелчком на соответствующем флажке) выводится список дескрипторов, открытых процессом, а также список модулей (например, DLL), загруженных в адресное пространство процесса. Поле Найти дескрипторы (Search Handles) также может использоваться для поиска процессов, открывших дескриптор для заданного именованного ресурса.

На вкладке Память (Memory) отображается практически та же информация, которая может быть получена с помощью диспетчера задач, но упорядоченная для всей системы. На графике физической памяти выводится текущее распределение

1-37.tif 

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

С другой стороны, на вкладке Диск (Disk) выводится информация ввода/вывода уровня файлов, которая позволяет легко определять, к каким файлам в системе происходит больше всего обращений, чаще всего выполняется запись или чтение. Результаты можно дополнительно отфильтровать по процессам.

На вкладке Сеть (Network) выводятся активные сетевые подключения, процессы, которым они принадлежат, и объем данных, проходящих через них. Эти данные позволяют обнаружить фоновую сетевую активность, которую трудно обнаружить другими способами. Кроме того, на вкладке отображаются подключения TCP, активные в системе, упорядоченные по процессам с такими данными, как удаленный и локальный порт, адрес и время задержки пакетов. Также выводится список прослушиваемых портов для процессов, по которому администратор может определить, какие службы или приложения в настоящее время ожидают подключений через конкретный порт. Для каждого порта указывается протокол и политика брандмауэра.

ПРИМЕЧАНИЕ Ко всем счетчикам производительности Windows можно обращаться на программном уровне. Для получения дополнительной информации проведите поиск по условию «счетчики производительности» в документации MSDN.

Отладка ядра

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

Прежде чем описывать различные способы отладки ядра, рассмотрим некоторые файлы, которые понадобятся вам для выполнения любой разновидности отладки ядра.

Символическая информация для отладки ядра

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

Чтобы использовать любые средства отладки ядра для анализа внутренних структур данных ядра Windows — таких, как списки процессов, блоки потоков, списки загруженных драйверов, информация об использовании памяти и т.д. — необходимо иметь нужные символические файлы хотя бы для образа ядра Ntoskrnl.exe. (Этот файл более подробно описан в разделе «Обзор архитектуры» главы 2.) Файлы символических таблиц должны соответствовать версии того образа, на основании которого они были построены. Например, при установке обновления или исправления Windows с модификацией ядра вы должны найти для него соответствующие символические файлы.

И хотя вы можете загрузить и установить символическую информацию для разных версий Windows, обновленные символические файлы для исправлений доступны не всегда. Самый простой способ получить правильную версию символических данных для отладки — воспользоваться сервером символической информации Microsoft с использованием специального синтаксиса пути к символическим данным, который задается в отладчике. Например, следующий путь заставляет средства отладки загрузить необходимую символическую информацию с сервера в интернете и сохранить локальную копию в папке C:\symbols:

srv*c:\symbols*

Средства отладки для Windows

Пакет средств отладки (Debugging Tools) для Windows содержит расширенные средства отладки, использованные в книге для анализа внутренней структуры Windows. Новейшая версия включается в Windows SDK. (За дополнительной информацией о различных типах установки обращайтесь по адресу .) Эти средства могут использоваться как для отладки процессов пользовательского режима, так и для отладки процессов ядра.

В пакет включены четыре отладчика: cdb, ntsd, kd и WinDbg. Все они основаны на одном отладочном механизме, реализованном в библиотеке DbgEng.dll; он достаточно хорошо документирован в справочном файле. Краткий обзор отладчиков:

• cdb и ntsd — отладчики пользовательского режима с консольным интерфейсом. Они различаются только одним: при запуске из существующего консольного окна ntsd открывает новое консольное окно, а cdb этого не делает.

• kd — отладчик режима ядра с консольным интерфейсом.

• WinDbg может использоваться как отладчик либо пользовательского режима, либо режима ядра, но не одновременно. Отладчик предоставляет графический интерфейс.

Отладчики пользовательского режима (cdb, ntsd и WinDbg, когда используется в этом режиме) практически эквивалентны. Выбор того или иного варианта зависит от личных предпочтений.

Отладчики режима ядра (kd и WinDbg, когда используется в этом режиме) тоже эквивалентны.

Отладка пользовательского режима. Средства отладки также могут присоединяться к процессам пользовательского режима для анализа и/или изменения содержимого памяти процессов. При подключении к процессу возможны два варианта:

• Агрессивный (Invasive). Если явно не указано обратное, при подключении к работающему процессу функция Windows DebugActiveProcess используется для установления связи между отладчиком и отлаживаемым процессом. Это позволяет вам анализировать и/или изменять память процесса, расставлять точки останова и выполнять другие отладочные операции. Windows позволяет прервать отладку без уничтожения целевого процесса при условии, что отладчик отсоединяется (а не уничтожается).

• Неагрессивный. В этом варианте отладчик просто открывает процесс функцией OpenProcess. Он не присоединяется к процессу как отладчик. Вы сможете анализировать и/или изменять память целевого процесса, но не назначать точки останова. Это также означает, что неагрессивное подключение возможно, даже если другой отладчик уже присоединился агрессивно.

Также средствами отладки можно открывать файлы дампа процессов пользовательского режима. Файлы дампа рассматриваются в главе 8 части 2, в разделе, посвященном диспетчеризации исключений.

Отладка режима ядра. Как упоминалось ранее, для отладки ядра могут использоваться два отладчика: с интерфейсом командной строки (Kd.exe) и версия с графическим интерфейсом (Windbg.exe). С этими средствами можно выполнять три разновидности отладки режима ядра:

• Открыть файл аварийного дампа, созданный в результате сбоя системы Windows. (За информацией об аварийных дампах ядра обращайтесь к главе 15 «Анализ аварийного дампа», часть 2.)

• Подключение к «живой», работающей системе и анализ состояния системы (или назначение точек останова, если вы занимаетесь отладкой кода драйверов устройств). Для этой операции нужны два компьютера: целевой (отлаживаемая система) и хост (система, в которой работает отладчик). Целевая система также может быть подключена к хосту нуль-модемным кабелем, кабелем IEEE 1394, отладочным кабелем USB 2.0/3.0 или по локальной сети. Целевая система должна загружаться в отладочном режиме. Систему можно настроить для загрузки в отладочном режиме при помощи программы Bcdedit.exe или Msconfig.exe. (Возможно, для этого вам придется отключить безопасную загрузку в настройках BIOS UEFI.) Также возможно подключение через именованный канал — это имеет смысл при отладке Windows 7 или более ранних версий через виртуальную машину, такую как Hyper-V, Virtual Box или VMWare Workstation, предоставлением доступа к последовательному порту гостевой операционной системы как к устройству именованного канала. Для Windows 8 и более поздних гостевых версий вам придется использовать отладку локальной сети, предоставляя сеть, состоящую только из хоста, с использованием виртуальной сетевой платы в гостевой операционной системе. Это приводит к 1000-кратному приросту быстродействия.

• Системы Windows также позволяют подключаться к локальной системе и анализировать ее состояние (это называется локальной отладкой ядра). Чтобы инициировать локальную отладку ядра в WinDbg, сначала убедитесь в том, что система переведена в отладочный режим (например, запустите msconfig.exe, перейдите на вкладку Загрузка (Boot), щелкните на кнопке Дополнительные параметры (Advanced Options), выберите вариант Отладка (Debug) и перезапустите Windows). Запустите WinDbg с привилегиями администратора, откройте меню File, выберите команду Kernel Debug, перейдите на вкладку Local и щелкните на кнопке OK (или используйте bcdedit.exe). На рис. 1.6 показан пример вывода для 64-разрядной машины с Windows 10. Некоторые команды отладчика ядра не работают в режиме локальной отладки ядра (например, назначение точек останова или создание дампа памяти командой .dump). Впрочем, последнее можно сделать с помощью программы LiveKd, описанной далее в этом разделе.

FIGURE%201-6.tif 

Рис. 1.6. Локальная отладка ядра

После подключения в режиме отладки ядра вы сможете воспользоваться многочисленными командами расширения отладчика (эти команды начинаются с восклицательного знака (!)) для просмотра содержимого внутренних структур данных: потоков, процессов, пакетов запросов ввода/вывода и информации управления памятью. В этой книге при обсуждении каждой темы приводятся связанные с этой темой команды отладчика ядра и примеры вывода. Отличным источником информации служит справочный файл Debugger.chm из папки установки WinDbg: он документирует всю функциональность и расширения отладчика ядра. Кроме того, команда dt (Display Type) может вывести в отформатированном виде более 1000 структур ядра, потому что файлы с символической информацией ядра для Windows содержат данные, которые могут использоваться отладчиком для форматирования структур.

Эксперимент: вывод информации типа для структур данных ядра

Чтобы вывести список структур ядра, данные типа которых содержатся в символической информации ядра, введите команду dt nt!_* в отладчике ядра. Ниже приведен пример части вывода (ntkrnlmp — внутреннее имя файла 64-разрядного ядра. За подробностями обращайтесь к главе 2).

lkd> dt nt!_*

         ntkrnlmp!_KSYSTEM_TIME

         ntkrnlmp!_NT_PRODUCT_TYPE

         ntkrnlmp!_ALTERNATIVE_ARCHITECTURE_TYPE

         ntkrnlmp!_KUSER_SHARED_DATA

         ntkrnlmp!_ULARGE_INTEGER

         ntkrnlmp!_TP_POOL

         ntkrnlmp!_TP_CLEANUP_GROUP

         ntkrnlmp!_ACTIVATION_CONTEXT

         ntkrnlmp!_TP_CALLBACK_INSTANCE

         ntkrnlmp!_TP_CALLBACK_PRIORITY

         ntkrnlmp!_TP_CALLBACK_ENVIRON_V3

         ntkrnlmp!_TEB

Команда dt также может использоваться с универсальными символами для поиска структур. Например, если вы ищете имя структуры для объекта прерывания, введите команду dt nt!_*interrupt*:

lkd> dt nt!_*interrupt*

         ntkrnlmp!_KINTERRUPT_MODE

         ntkrnlmp!_KINTERRUPT_POLARITY

         ntkrnlmp!_PEP_ACPI_INTERRUPT_RESOURCE

         ntkrnlmp!_KINTERRUPT

         ntkrnlmp!_UNEXPECTED_INTERRUPT

         ntkrnlmp!_INTERRUPT_CONNECTION_DATA

         ntkrnlmp!_INTERRUPT_VECTOR_DATA

         ntkrnlmp!_INTERRUPT_HT_INTR_INFO

         ntkrnlmp!_INTERRUPT_REMAPPING_INFO

Далее найденная структура форматируется командой dt (отладчик игнорирует регистр символов):

lkd> dt nt!_KINTERRUPT

   +0x000 Type             : Int2B

   +0x002 Size             : Int2B

   +0x008 InterruptListEntry : _LIST_ENTRY

   +0x018 ServiceRoutine   : Ptr64     unsigned char

   +0x020 MessageServiceRoutine : Ptr64    unsigned char

   +0x028 MessageIndex     : Uint4B

   +0x030 ServiceContext   : Ptr64 Void

   +0x038 SpinLock         : Uint8B

   +0x040 TickCount        : Uint4B

   +0x048 ActualLock       : Ptr64 Uint8B

   +0x050 DispatchAddress  : Ptr64     void

   +0x058 Vector           : Uint4B

   +0x05c Irql             : UChar

   +0x05d SynchronizeIrql  : UChar

   +0x05e FloatingSave     : UChar

   +0x05f Connected        : UChar

   +0x060 Number           : Uint4B

   +0x064 ShareVector      : UChar

   +0x065 EmulateActiveBoth : UChar

   +0x066 ActiveCount      : Uint2B

   +0x068 InternalState    : Int4B

   +0x06c Mode             : _KINTERRUPT_MODE

   +0x070 Polarity         : _KINTERRUPT_POLARITY

   +0x074 ServiceCount     : Uint4B

   +0x078 DispatchCount    : Uint4B

   +0x080 PassiveEvent     : Ptr64 _KEVENT

   +0x088 TrapFrame        : Ptr64 _KTRAP_FRAME

   +0x090 DisconnectData   : Ptr64 Void

   +0x098 ServiceThread    : Ptr64 _KTHREAD

   +0x0a0 ConnectionData   : Ptr64 _INTERRUPT_CONNECTION_DATA

   +0x0a8 IntTrackEntry    : Ptr64 Void

   +0x0b0 IsrDpcStats      : _ISRDPCSTATS

   +0x0f0 RedirectObject   : Ptr64 Void

   +0x0f8 Padding          : [8] UChar

Обратите внимание: команда dt по умолчанию не выводит субструктуры (структуры внутри структур). Для вывода субструктур используется ключ -r или -b. Например, при использовании одного из этих ключей объект прерывания ядра выводит формат структуры _LIST_ENTRY, хранящейся в поле InterruptListEntry. (Различия между ключами -r и -b описаны в документации.)

lkd> dt nt!_KINTERRUPT -r

   +0x000 Type           : Int2B

   +0x002 Size           : Int2B

   +0x008 InterruptListEntry : _LIST_ENTRY

      +0x000 Flink       : Ptr64 _LIST_ENTRY

          +0x000 Flink      : Ptr64 _LIST_ENTRY

          +0x008 Blink      : Ptr64 _LIST_ENTRY

      +0x008 Blink       : Ptr64 _LIST_ENTRY

          +0x000 Flink      : Ptr64 _LIST_ENTRY

          +0x008 Blink      : Ptr64 _LIST_ENTRY

   +0x018 ServiceRoutine   : Ptr64     unsigned char

Команда dt даже позволяет задать уровень рекурсии структур; нужное число указывается за ключом -r. В следующем примере выбирается один уровень рекурсии:

lkd> dt nt!_KINTERRUPT -r1

В справочном файле средств отладки для Windows объясняется, как настроить и использовать отладчики ядра. За дополнительной информацией об использовании отладчиков ядра, предназначенной прежде всего для разработчиков драйверов устройств, обращайтесь к документации WDK.

Программа LiveKd

LiveKd — бесплатная программа из пакета Sysinternals, которая позволяет использовать только что описанные стандартные отладчики ядра компании Microsoft без загрузки системы в отладочном режиме. Такое решение может использоваться в ситуации, когда требуется провести диагностику уровня ядра на машине, не загруженной в отладочном режиме. Некоторые проблемы трудно надежно воспроизвести, поэтому при перезагрузке в отладочном режиме проблема может и не проявиться.

LiveKd запускается так же, как WinDbg или kd. LiveKd передает все заданные вами параметры командной строки выбранному вами отладчику. По умолчанию LiveKd запускает отладчик ядра с интерфейсом командной строки (kd). Чтобы он запускал WinDbg, используйте ключ -w. Для просмотра описаний ключей LiveKd используйте ключ -?.

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

Если отладчик зацикливается при выводе, нажмите Ctrl+C, чтобы прервать вывод и завершить работу. Если отладчик зависнет, нажмите Ctrl+Break — эта комбинация завершает процесс отладки. В этом случае LiveKd предложит перезапустить отладчик.

Windows Software Development Kit

Пакет Windows SDK (Software Development Kit) доступен в составе подписки MSDN. Его можно бесплатно загрузить по адресу . Visual Studio также предоставляет возможность установить SDK как часть установки VS. Версии, содержащиеся в Windows SDK, всегда соответствуют новейшей версии операционной системы Windows, тогда как в составе Visual Studio может поставляться более старая версия, актуальная на момент выпуска. Кроме средств отладки Windows она содержит заголовочные файлы C и библиотеки, необходимые для компиляции и компоновки приложений Windows. С позиций внутреннего устройства Windows в Windows SDK заслуживают внимания заголовочные файлы Windows API, например C:\Program Files (x86)\Windows Kits\10\Include, и инструментальные средства SDK (поищите папку Bin). Также стоит обратить внимание на документацию: вы можете работать с ней в интернете или загрузить для автономной работы. Некоторые средства также поставляются в виде примеров исходного кода для Windows SDK и MSDN Library.

Windows Driver Kit

Пакет WDK (Windows Driver Kit) также доступен в программе подписки MSDN. Как и Windows SDK, его можно загрузить бесплатно. Документация WDK включена в MSDN Library.

Хотя пакет WDK предназначен для разработчиков драйверов устройств, это богатый источник информации о внутреннем устройстве Windows. Например, хотя в главе 6 описывается архитектура системы ввода/вывода, модель драйверов и базовые структуры данных драйверов устройств, в ней отсутствует подробное описание отдельных функций поддержки ядра. Документация WDK содержит подробное описание всех функций поддержки ядра Windows и механизмов, используемых драйверами устройств, как в форме учебника, так и в форме справочника.

Кроме документации WDK содержит заголовочные файлы (прежде всего ntddk.h, ntifs.h и wdm.h) с определениями ключевых внутренних структур данных и констант, а также интерфейсов ко многим внутренним системным функциям. Эти файлы помогают в исследовании внутренних структур данных Windows с отладчиком ядра; хотя в книге приводится общее строение и содержимое этих структур, подробных описаний уровня полей (размеры и типы данных) мы не приводим. Впрочем, некоторые структуры данных — заголовки диспетчеризации объектов, блоки ожидания, события, мутанты, семафоры и т.д. — полностью описаны в WDK.

Если вы захотите изучить систему ввода/вывода и модель драйверов более подробно, читайте документацию WDK — особенно руководства Kernel-Mode Driver Architecture Design Guide и Kernel-Mode Driver Reference. Также вам могут пригодиться книги Programming the Microsoft Windows Driver Model, Second Edition Уолтера Они (Walter Oney) (Microsoft Press, 2002) и Developing Drivers with the Windows Driver Foundation Пенни Орвик (Penny Orwick) и Гая Смита (Guy Smith)(Microsoft Press, 2007).

Средства Sysinternals

Во многих экспериментах в книге используются бесплатные программы, которые можно загрузить на сайте Sysinternals. Большинство из них написал Марк Руссинович, соавтор этой книги. Самые популярные программы пакета — Process Explorer и Process Monitor. Учтите, что многие из этих программ требуют установки и выполнения драйверов режима ядра, а для этого необходимы привилегии администратора, хотя некоторые могут запускаться с ограниченной функциональностью и выводом из стандартной (непривилегированной) учетной записи пользователя.

Так как средства Sysinternals часто обновляются, следите за тем, чтобы у вас была установлена новейшая версия. Чтобы получать оповещения об обновлениях инструментария, следите за блогом на сайте Sysinternals (у которого также имеется новостной канал RSS). Описания всех программ, информация об их использовании и практические примеры решения проблем приведены в книге Windows Sysinternals Administrator’s Reference Марка Руссиновича (Mark Russinovich) и Аарона Маргосиса (Aaron Margosis) (Microsoft Press, 2011). С вопросами и обсуждениями обращайтесь на форумы Sysinternals.

Заключение

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

Итак, к началу исследования внутреннего устройства системы все готово. Начнем с общего обзора архитектуры системы и ее ключевых компонентов.

Здесь и далее используются ссылки на вторую часть книги, которая на момент выпуска пер­вого тиража русскоязычного перевода еще не опубликована (находится в работе у авторов).

Показать оглавление

Комментариев: 6

Оставить комментарий

  1. JamesCen
    scottsdale health care studiomerliniortodonzia.it/cgi-bin/antibiotici.htm health care communities
  2. Franksog
    home remedy gingivitis studiomerliniortodonzia.it/cgi-bin/antibiotici.htm infant fever remedies
  3. KennethLib
    knee ache remedies studiomerliniortodonzia.it/cgi-bin/testosterone.htm lifetime health care
  4. KennethLib
    knee ache remedies studiomerliniortodonzia.it/cgi-bin/testosterone.htm lifetime health care
  5. KennethLib
    knee ache remedies studiomerliniortodonzia.it/cgi-bin/testosterone.htm lifetime health care
  6. KennethLib
    knee ache remedies studiomerliniortodonzia.it/cgi-bin/testosterone.htm lifetime health care