MicrosoftWindows:
Windows Server™ 2003, Windows XP и Windows 2000
4-е издание
Посвящается Дэйву Катлеру - отцу ядра Windows
Предыстория
Я вновь признателен Дэвиду Соломону (David Solomon) и Марку Руссиновичу (Mark Russinovich) за то, что они предоставили мне возможность сказать несколько слов о новом издании их книги «Внутреннее устройство Microsoft Windows». Прошло уже более трех лет с момента выхода последнего издания этой книги, и за это время на свет появились два выпуска операционной системы Windows - очень значимые обновления клиентской и серверной систем.
Перед авторами стояли две задачи, которые постоянно усложняются: отслеживание эволюционного развития системы Microsoft Windows NT и документирование того, как менялась реализация ее компонентов в каждой версии. B этом смысле авторы проделали просто выдающуюся работу.
(Слева направо) Дэвид Соломон, Дэвид Катлер и Марк Руссинович
Впервые я познакомился с Дэвидом Соломоном, когда ему было всего 16 лет, а я работал в Digital Equipment Corporation над операционной системой VMS для VAX. C тех пор он участвовал в разработке операционных систем, а также преподавал в этой области. C Марком Руссиновичем я познакомился позже, но уже задолго до этого был немало наслышан о его глубоких познаниях в области операционных систем. B числе его заслуг версия файловой системы NTFS, которую он заставил работать в Microsoft Windows 98, и «живой» отладчик ядра Windows, позволяющий заглянуть внутрь системы Windows в процессе ее выполнения.
Истоки Windows NT восходят к октябрю 1988 года, когда было решено создать переносимую операционную систему, совместимую с OS/2, поддерживающую POSIX и многопроцессорную обработку, обладающую высокой защищенностью, надежностью и интегрированными средствами работы в сетях. C приходом Windows 3.0 и ее колоссальным успехом заявленные цели несколько изменились: совместимость с OS/2 была перенесена с уровня всей системы на уровень отдельной подсистемы.
Поначалу мы полагали, что сумеем создать Windows NT за пару лет, но в действительности ее первая версия вышла лишь через четыре с половиной года - летом 1993-го. Эта версия поддерживала процессоры Intel i386, Intel i486 и MIPS R4000. Шесть недель спустя мы ввели поддержку и для процессоров Digital Alpha.
Первая версия Windows NT получилась более громоздкой и медленной, чем ожидалось, так что следующей вехой стал проект Daytona (так называется автострада во Флориде). Главной целью в этой версии было уменьшение размера системы, повышение ее быстродействия и, разумеется, надежности. Через полгода после выпуска Windows NT 3.5 осенью 1994-го мы подготовили Windows NT 3.51, которая представляла собой обновленную версию с дополнительной поддержкой процессора IBM PowerPC.
Толчком к созданию следующей версии Windows NT стало желание сделать пользовательский интерфейс, совместимый с Windows 95, и включить технологии Cairo, уже находившиеся в разработке пару лет. Ha создание этой системы ушло еще два года, и летом 1996 года была представлена Windows NT 4.0.
Название следующей версии NT было изменено на Windows 2000. Она стала последней системой, для которой одновременно выпускались клиентская и серверная версии. Windows 2000 была построена на той же технологии Windows NT, что и предыдущие версии, но обладала новой важной функциональностью, поддерживая, в частности, Active Directory. Ha разработку Windows 2000 ушло три с половиной года, и на тот период она была самой оптимизированной и наиболее тщательно протестированной версией технологии Windows NT Windows 2000 стала кульминацией более чем одиннадцатилетних разработок, реализованных на четырех архитектурах.
B конце разработки Windows 2000 мы приступили к работе над амбициозным планом реализации новых версий клиентской и серверной систем, которые должны были предоставить новые, более совершенные возможности потребителям и улучшить характеристики серверов. Ho потом стало ясно, что реализация серверных средств привела бы к задержке в реализации клиентских, и поэтому было решено разделить выпуски. B августе 2001 года на свет появились Windows XP Professional и Windows XP Home Edition, a через год с небольшим, в марте 2003 года была выпущена Microsoft Windows Server 2003. Помимо архитектуры Intel x86, эти системы поддерживали Intel IA64, благодаря чему Windows NT впервые вышла на стезю 64-разрядных вычислений.
Эта книга единственная, где так глубоко и полно рассмотрены внутренние структуры и принципы функционирования Windows XP и Windows Server
2003. Кроме того, она предлагает заглянуть в будущее - перевод Windows на 64-разрядные «рельсы», т. е. на ее поддержку архитектур x64 (AMD64) и Intel EM64T, объявленных AMD в 2003 году и Intel в феврале 2004 года соответственно. Выпуск клиентской и серверной версий с полной поддержкой x64 запланирован на первую половину 2005 года, и в этой книге содержится масса информации о внутренних деталях реализации х64-системы.
Архитектура х64 - это начало новой эры для Windows NT в тот момент, когда время архитектуры x86 подходит к концу. Архитектура x64 обеспечивает совместимость с 32-разрядной х86-платформой и предоставляет 64-разрядную адресацию для наиболее требовательных, совершенно новых приложений. Это позволит сохранить инвестиции в 32-разрядное программное обеспечение, в то же время вдохнув новую жизнь в Windows NT на ближайшее десятилетие или даже на более длительный период.
Хотя название NT-системы за последние несколько лет неоднократно менялось, она по-прежнему полностью основана на исходной кодовой базе Windows NT. Ho время бежит, появляются новые технологии, и реализация многих внутренних компонентов и функций значительно изменилась. Авторы проделали внушительную работу, собрав столько детальной информации о кодовой базе Windows NT и ее реализациях в разных выпусках на разных платформах, а также создав примеры и утилиты, которые помогают читателю разобраться в том, как работают компоненты и подсистемы Windows. Экземпляр этой книги должен лежать на столе у каждого разработчика серьезного программного обеспечения.
Дэвид H. Катлер, заслуженный старший инженер корпорации Microsoft
Предисловие
Microsoft Windows была частью моей жизни целых 14 лет. За это время - от версии к версии - наша операционная система развивалась вширь и вглубь. Сегодня работа над Windows - один из самых важных и сложных проектов в мире. B выпуске Windows участвуют более 5000 инженеров. Среди пользователей Windows есть представители уже почти всех культур, она используется как на крупных предприятиях, так и маленькими детьми. Пользователи Windows постоянно требуют ее совершенствования практически во всех сферах - от эффективной работы на крупнейших серверах до применения в дошкольном обучении. Windows поставляется в самых разных ипостасях - от встраиваемых версий и выпусков для медиа-центров до редакций для центров обработки данных. Все эти продукты опираются на одни и те же базовые компоненты Windows, которые развиваются и совершенствуются в каждой новой версии.
Это фундаментальная книга о внутреннем устройстве базовых компонентов Windows. Если вы хотите как можно быстрее освоить принципы внутренней работы Windows, тогда эта книга для вас. Освоение всех частей столь основательного продукта - задача устрашающая. Ho если вы начнете с базовых концепций системы, сложить фрагменты головоломки воедино будет гораздо легче. C эволюцией самой Windows развивается и эта книга - сейчас публикуется ее четвертое издание. Мы уже давно используем ее для обучения новых сотрудников Microsoft, так что предлагаемые вам материалы проверены на практике.
Если вы вроде меня, значит, вам тоже нравится разбираться в том, как устроены вещи. Чтение книжек типа «как использовать то-то и то-то» меня никогда не удовлетворяло. Когда понимаешь, как именно устроена вещь, пользуешься ею гораздо эффективнее и, честно говоря, с большим удовольствием. Если вас интересует Windows «с изнанки», вы выбрали подходящую книгу.
Дэвид и Марк проделали превосходную работу, написав книгу о технической «изнанке» Windows. A инструменты, которые они предлагают вам, - отличное средство для самостоятельного обучения и диагностики. Прочитав эту книгу, вы будете гораздо лучше понимать, как взаимодействуют между собой различные компоненты и подсистемы, какие усовершенствования внесены в новую версию и как выжать из них максимум возможного.
Это был долгий путь - и он все еще продолжается. Так что открывайте книгу, а заодно и капот, под которым бьется сердце одной из самых потрясающих операционных систем.
Джим Олчин,
вице-президент группы платформ корпорации Microsoft
Благодарности
B первую очередь мы хотим особо поблагодарить следующих людей.
(o) Дэйва Катлера(Dave Cutler), заслуженного старшего инженера и первого архитектора Microsoft Windows NT. Дэйв разрешил Дэвиду Соломону (David Solomon) доступ к исходному коду и всячески поддерживал его преподавательскую деятельность, посвященную объяснению деталей внутреннего устройства Windows NT, а также его работу над вторым и третьим изданием книги. Помимо рецензирования главы по процессам и потокам, Дэйв ответил на массу вопросов об архитектуре ядра и написал об истории создания Windows для нашей книги.
(o)
Джима ОлчинаJim Allchin), нашего главного спонсора, - за предисловие к этой книге и за отстаивание интересов нашего дела в Microsoft.
(o)
Роба Шорта(Rob Short), вице-президента, который позаботился о том, чтобы нам предоставили ресурсы и доступ к нужным людям.
Мы также выражаем признательность двум разработчикам из отдела Windows за подготовку новых материалов, включенных в это издание:
(o) Адриану Маринеску(Adrian Marinescu), который написал заметно разросшийся раздел по диспетчеру куч в главе, где рассматривается диспетчер памяти.
(o) Самеру Арафеху(Samer Arafeh), который предоставил материалы по Wow64.
Спасибо нашему старому приятелю, Джеффри Рихтеру Jeffrey Richter), с которым мы часто вместе обедаем, за врезку «Как насчет .NET и WinFX?» в главе 1 и за постоянное напоминание о том, как мало людей, по-настоящему интересующихся тем, о чем мы говорим в своей книге.
B этой книге не было бы такой глубины и точности изложения технических сведений без поддержки, замечаний и предложений ключевых членов команды разработчиков Microsoft Windows. Вот эти люди:
Были и другие, кто отвечал на наши вопросы в коридорах или кафетериях, - если мы вас пропустили, пожалуйста, простите нас!
Мы также выражаем благодарность Джейми Ханрахан Jamie Hanrahan) из Azius Developer Training
(www.azius.com),которая в соавторстве с Дэвидом подготовила учебный курс по внутренней архитектуре исходной версии Windows. Ha основе этого курса было написано второе издание этой книги. Джейми, у которой настоящий талант доходчиво объяснять сложнейшие вещи, предоставила нам отдельные материалы, а также ряд схем и иллюстраций.
Спасибо Дэйву Проберту (Dave Probert) за то, что разместил в сети наши черновые материалы для распространения среди рецензентов внутри Microsoft.
Благодарим Джонатана Славза (Jonathan Sloves) из AMD, с помощью которого нам предоставили тестовые системы AMD64; они очень помогли нам в написании материалов по 64-разрядной архитектуре и в переносе ряда утилит Sysinternals на платформу x64.
Наконец, мы хотим выразить благодарность следующим сотрудникам Microsoft Press за их вклад в эту книгу.
(o) Робину Ван-Штеенбергу(Robin van Steenburgh), рецензенту издательства, за терпение в работе с нами над этим проектом.
(o) Салли Стикни(Sally Stickney), которая на первых порах по-прежнему была редактором нашего проекта, но потом ее закрутил водоворот административных дел. Мы очень скучали без вас!
(o) Валери Вулли(Valerie Woolley), которая приняла бразды правления от Салли и стала нашим новым редактором проекта. Вы замечательная и не такая резкая, как Салли!
(o) РоджеруЛебланку(Roger LeBlanc), который одолел все главы и сумел сократить в них текст, найти несогласованности и вообще довести нашу рукопись до высоких стандартов Microsoft Press.
Дэвид Соломон иМаркРуссинович сентябрь 2004 г.
Введение
Четвертое издание этой книги ориентировано на квалифицированных специалистов (программистов, разработчиков и системных администраторов), желающих разобраться в принципах внутренней работы основных компонентов операционных систем Microsoft Windows 2000, Microsoft Windows XP и Microsoft Windows Server 2003. Зная их, разработчики смогут принимать более эффективные решения на этапах проектирования приложений для платформы Windows. Такие знания помогут программистам и в отладке - при устранении сложных проблем. Информация, изложенная в книге, будет также полезна системным администраторам: понимание того, как устроена и работает операционная система, упростит им оптимизацию своих систем и устранение неполадок в случае каких-либо сбоев. Прочитав эту книгу, вы лучше поймете, как функционирует Windows и почему она ведет себя именно так, а не как-то иначе.
Структура книги
Первые две главы закладывают фундамент, вводя термины и концепции, используемые во всей книге. Следующие три главы описывают ключевые механизмы операционной системы. B следующих восьми главах детально рассматриваются базовые компоненты Windows - процессы, потоки и задания, управление памятью, защита, подсистема ввода-вывода, управление внешней памятью, диспетчер кэша, файловые системы и поддержка сетей. Наконец, в последней главе поясняется, как проводить анализ аварийных дампов памяти.
История написания книги
Это четвертое издание книги, которая изначально называлась «Inside Windows NT» (Microsoft Press, 1992) и была написана Хелен Кастер (Helen Custer) еще до выпуска Microsoft Windows NT 3.1. Она стала первой книгой по Windows NT и представляла собой глубокий обзор архитектуры этой системы. Второе издание, «Inside Windows NT» (Microsoft Press, 1998), было написано Дэвидом Соломоном. B него вошла новая информация по Windows NT 4.0, а сама книга стала гораздо более глубокой. Третье издание, «Inside Windows 2000» (Microsoft Press, 2000), было подготовленоДэвидом Соломоном и Марком Руссиновичем. B нем появилось много новых тематических разделов, в том числе по этапам загрузки и завершения работы системы, внутреннему устройству сервисов и реестра, по драйверам файловых систем, поддержке
сетей, а также по новой функциональности ядра Windows 2000, например модели WDM, Plug and Play, WMI, шифрованию, Terminal Services и др.
Особенности четвертого издания
Новое издание дополнено информацией об изменениях в ядре, которые были внесены в Windows XP и Windows Server 2003, в том числе касающихся поддержки 64-разрядных систем. Материалы для экспериментов также были обновлены, чтобы отразить изменения в усовершенствованных утилитах и научить вас пользоваться новыми инструментами, которых не было на момент подготовки третьего издания.
Так как отличия новых версий Windows от Windows 2000 относительно невелики (по сравнению с различиями между Windows NT 4.0 и Windows 2000), основная часть книги равно применима к Windows 2000, Windows XP и Windows Server 2003. Поэтому, если не оговорено иное, все сказанное относится ко всем трем версиям.
Инструменты для проведения экспериментов
Даже без доступа к исходному коду существующие инструменты вроде отладчика ядра позволяют многое прояснить во внутреннем устройстве Windows. B том месте, где для демонстрации какого-либо аспекта поведения Windows используется тот или иной инструмент, во врезке «Эксперимент» даются инструкции по его применению. Такие врезки часто встречаются в книге, и мы рекомендуем вам проделывать эти эксперименты в процессе чтения: наглядно увидев, как ведет себя Windows в конкретной ситуации, вы гораздо лучше усвоите прочитанный материал.
Тематика, не рассматриваемая в книге
Windows - большая и сложная операционная система. Нельзя объять необъятное, и поэтому основное внимание в книге уделяется только базовым системным компонентам. Например, мы не рассматриваем COM+, инфраструктуру объектно-ориентированного программирования распределенных приложений для Windows, или .NET Framework, платформу для следующего поколения приложений с управляемым кодом.
Поскольку наша книга о внутреннем устройстве Windows, а не о том, как пользоваться этой операционной системой, программировать для нее или администрировать системы, созданные на ее основе, вы не найдете здесь никаких сведений об использовании, программировании и конфигурировании Windows.
Подводные камни
B книге описываются недокументированные внутренние структуры и функции ядра, архитектура и различные аспекты внутренней работы Windows, и часть таких структур и функций может измениться в следующем выпуске этой операционной системы. (Впрочем, внешние интерфейсы вроде Windows API всегда сохраняют совместимость с аналогичными интерфейсами в очередных выпусках.)
Говоря «может измениться», мы не имеем в виду, что детали устройства системы обязательно изменятся в следующем выпуске, а лишь обращаем внимание на то, что достоверность информации гарантируется исключительно для данных версий. Любое программное обеспечение, использующее недокументированные интерфейсы, может перестать работать в будущих версиях Windows. Более того, такое программное обеспечение, если оно работает в режиме ядра (как, например, драйверы устройств), может привести к краху более новых версий Windows.
Техническая поддержка
Мы приложили максимум усилий, чтобы не допустить неточностей и ошибок в книге. Если у вас возникнут какие-либо проблемы или вопросы, пожалуйста, обращайтесь по адресам, указанным в следующих двух разделах.
От авторов
Эта книга отнюдь не совершенна. Несомненно в ней есть какие-то неточности; может быть, мы упустили что-то важное. Если вы найдете то, что считаете ошибочным, или если вы сочтете, что в книгу следует включить дополнительный материал, пожалуйста, пошлите свое сообщение по адресу
win
.Обновления и исправления будут выкладываться на страницу
От Microsoft Press
Microsoft публикует исправления к книгам по адресу
com/learning/'support.Для прямого подключения к Microsoft Learning Knowledge Base и ввода запроса по проблеме, с которой вы столкнулись, заходите на страницу
. B переводе учтены исправления, опубликованные на этой Web-странице, по состоянию на 1 июля 2005 года. -
Прим. перев.
Г Л A B A 1 Концепции и инструменты
B этой главе мы познакомим вас с основными концепциями и терминами операционной системы Microsoft Windows, которые будут использоваться в последующих главах, в том числе с Windows API, процессами, потоками, виртуальной памятью, режимом ядра и пользовательским режимом, объектами, описателями (handles), защитой, реестром. Мы также расскажем об инструментах, с помощью которых вы сможете исследовать внутреннее устройство Windows. K ним относятся, например, отладчик ядра, оснастка Performance и важнейшие утилиты с сайта
.Кроме того, мы поясним, как пользоваться Windows Device Driver Kit (DDK) и Platform Software Development Kit (SDK) в качестве источника дополнительной информации о внутреннем устройстве Windows.
Вы должны хорошо понимать все, что написано в этой главе, - в остальной части книги мы предполагаем именно так.
Версии операционных систем Windows
Эта книга охватывает три последние версии операционной системы Microsoft Windows, основанные на кодовой базе Windows NT: Windows 2000, Windows XP (32- и 64-разрядные версии) и Windows Server 2003 (32- и 64-разрядные версии). Текст относится ко всем трем версиям, если не оговорено иное. B таблице 1-1 перечислены выпуски кодовой базы Windows NT, номера версий и названия продуктов.
Windows NT и Windows 95
При первом выпуске Windows NT компания Microsoft дала ясно понять, что это долгосрочная замена Windows 95 (и ее последующих выпусков - Windows 98 и Windows Millennium Edition). Вот список некоторых архитектурных различий и преимуществ Windows NT (и ее последующих выпусков) над Windows 95 (и ее последующими выпусками).
(o)Windows NT поддерживает многопроцессорные системы, a Windows 95 - нет.
(o)Файловая система Windows NT поддерживает средства защиты, например управление избирательным доступом (discretionary access control). B файловой системе Windows 95 этого нет.
(o)Windows NT - полностью 32-разрядная (а теперь и 64-разрядная) операционная система, в ней нет 16-разрядного кода, кроме того, который предназначен для выполнения 16-разрядных Windows-приложений. Windows 95 содержит большой объем старого 16-разрядного кода из предшествующих операционных систем - Windows 3.1 nMS-DOS.
(o)Windows NT полностью реентерабельна, а многие части Windows 95 нереентерабельны (в основном это касается 16-разрядного кода, взятого из Windows 3.1
).Большинство функций, связанных с графикой и управлением окнами (GDI и USER), включают именно нереентерабельный код. Когда 32-разрядное приложение в Windows 95 пытается вызвать системный сервис, реализованный как нереентерабельный 16-разрядный код, оно должно сначала получить общесистемную блокировку (или мьютекс), чтобы предотвратить вход других потоков в нереентерабельную кодовую базу. Еще хуже, что 16-разрядное приложение удерживает такую блокировку в течение всего времени своего выполнения. B итоге, хотя ядро Windows 95 содержит 32-разрядный планировщик с поддержкой мно-гопоточности и вытесняющей многозадачности, приложения часто работают как однопоточные из-за того, что большая часть системы реализована как нереентерабельный код.
(o)Windows NT позволяет выполнять 16-разрядные Windows-приложения в выделенном адресном пространстве, a Windows 95 всегда выполняет такие приложения в общем адресном пространстве, в котором они могут навредить друг другу и привести к зависанию системы.
(o)Разделяемая (общая) память процесса в Windows NT видна только тем процессам, которые имеют проекцию на один и тот же блок разделяемой памяти. B Windows 95 вся общая память видна и доступна для записи всем процессам. Таким образом, любой процесс может что-то записать и повредить какие-то данные в общей памяти, используемые другими процессами.
(o)Некоторые критически важные страницы памяти, занимаемые операционной системой Windows 95
,доступны для записи из пользовательского режима, а значит, обычное приложение может повредить содержимое этих страниц и привести к краху системы. Единственное, что умеет Windows 95 и чего никогда не смогут делать операционные системы на основе Windows NT, - выполнять
всестарые программы для MS-DOS и Windows 3.1 (а именно программы, требующие прямого доступа к оборудованию), а также 16-разрядные драйверы устройств MS-DOS. Если одной из основных целей разработки Windows 95 была 100%-я совместимость с MS-DOS и Windows 3.1, то исходной целью разработки Windows NT - возможность выполнения
большинствасуществующих 16-разрядных приложений при условии сохранения целостности и надежности системы.
Базовые концепции и термины
B книге будут часто встречаться ссылки на концепции и структуры, с которыми некоторые читатели, возможно, не знакомы. Здесь мы определимся с используемой в дальнейшем терминологией.
Windows API
Это системный интерфейс программирования в семействе операционных систем Microsoft Windows, включая Windows 2000, Windows XP, Windows Server 2003, Windows 95
,Windows 98
,Windows Millennium Edition (Me) и Windows CE. Каждая операционная система реализует разное подмножество Windows API. Windows 95
,Windows 98
,Windows Me и Windows CE в этой книге не рассматриваются.
ПРИМЕЧАНИЕWindows API описывается в документации Platform Software Development Kit (SDK). (См. раздел «Platform Software Development Kit (SDK)» далее в этой главе.) Этудокументацию можно бесплатно просмотреть на сайте
. Она также поставляется с Microsoft Developer Network (MSDN) всех уровней подписки. (MSDN - это программа Microsoft для поддержки разработчиков. Подробности см. на сайте
.) Отличное описание того, как программировать с использованием базового Windows API, см. в четвертом издании книги Джеффри Рихтера Jeffrey Richter) «Microsoft Windows для профессионалов» (Русская Редакция, 2000).
До появления 64-разрядных версий Windows XP и Windows Server 2003 интерфейс программирования 32-разрядных версий операционных систем Windows назывался Win32 API, чтобы отличать его от исходного 16-разрядного Windows API. B этой книге термин «Windows API» относится к 32-разряд-
ному интерфейсу программирования Windows 2000, а также к 32- и 64-разрядным интерфейсам программирования Windows XP и Windows Server 2003.
Windows API включает тысячи вызываемых функций, которые сгруппированы в следующие основные категории:
(o)базовые сервисы (Base Services);
(o)сервисы компонентов (Component Services);
(o)сервисы пользовательского интерфейса (User Interface Services);
(o)сервисы графики и мультимедиа (Graphics and Multimedia Services);
(o)коммуникационное взаимодействие и совместная работа (Messaging and Collaboration);
(o)сети (Networking);
(o)Web-сервисы (Web Services).
Основное внимание в нашей книге уделяется внутреннему устройству ключевых базовых сервисов, в частности поддержки процессов и потоков (threads), управления памятью, ввода-вывода и защиты.
Как насчет .NET и WinFX?
.NET Framework состоит из библиотеки классов, называемой Framework Class Library (FCL), и общеязыковой исполняющей среды (Common Language Runtime, CLR), которая предоставляет среду для выполнения управляемого кода с такими возможностями, как компиляция по требованию (just-in-time compilation, JIT compilation), верификация типов, сбор мусора и защита по правам доступа кода (code access security). Благодаря этому CLR создает среду разработки, которая повышает продуктивность труда программистов и уменьшает вероятность появления распространенных ошибок программирования. Отличное описание .NET Framework и ее базовой архитектуры см. в книге Джеффри Рихтера «Программирование на платформе Microsoft .NET Frame-work» (Русская Редакция, 2003).
CLR реализована как классический СОМ-сервер, код которой хранится в стандартной Windows DLL пользовательского режима. Фактически все компоненты .NET Framework реализованы как стандартные Windows DLL пользовательского режима, занимающие уровень поверх неуправляемых функций Windows APL (Никакие компоненты .NET Framework не работают в режиме ядра.) Ha рис. 1 -1 показаны взаимосвязи этих компонентов.
WinFX - «новый Windows API». Это результат эволюционного развития .NET Framework, которая будет поставляться с версией Windows под кодовым названием «Longhorn», следующим выпуском Windows. WinFX также можно установить в Windows XP и Windows Server 2003. WinFX образует фундамент для приложений следующего поколения, создаваемых для операционной системы Windows.
История создания Win32 API
Интересно, что поначалу Win32 не рассматривался как интерфейс программирования для Microsoft Windows NT. Поскольку проект Windows NT начинался как замена OS/2 версии 2, основным интерфейсом программирования был 32-разрядный OS/2 Presentation ManagerAPI. Однако год спустя на рынке появилась Microsoft Windows 3.0, быстро ставшая очень популярной. B результате Microsoft сменила курс и перенацелила проект Windows NT на будущую замену семейства продуктов Windows, а не OS/2. Вот на этом-то перепутье и встал вопрос о создании Windows API - до этого Windows API существовал только как 16-разрядный интерфейс.
Хотя в Windows API должно было появиться много новых функций, отсутствующих в Windows 3.1, Microsoft решила сделать новый API по возможности совместимым с именами функций, семантикой и типами данных в 16-разрядном Windows API, чтобы максимально облегчить бремя переноса существующих 16-разрядных Windows-приложений в Windows NT Поэтому тот, кто, впервые глядя на Windows API, удивляется, почему многие имена и интерфейсы функций кажутся противоречивыми, должен учитывать, что одной из причин такой противоречивости было стремление сделать Windows API совместимым со старым 16-разрядным Windows API.
Сервисы, функции и процедуры
Несколько терминов в документации Windows для пользователей и программистов имеет разный смысл в разных контекстах. Например, понятие «сервис» (service) может относиться к вызываемой функции операционной системы, драйверу устройства или серверному процессу (в последнем случае сервис часто называют службой). Ниже показано, что означают подобные термины в этой книге.
(o)
Функции Windows APIДокументированные, вызываемые подпрограммы в Windows API, например
CreateProcess, CreateFileи
GetMessage.
(o) Неуправляемые («родные») системные сервисы (или исполняемые системные сервисы)Недокументированные низкоуровневые сервисы операционной системы, которые можно вызывать в пользовательском режиме. Так,
NtCreateProcess- это внутрисистемный сервис, вызываемый Windows-функцией
CreateProcessпри создании нового процесса. (Определение неуправляемых функций см. в разделе «Диспетчеризация системных сервисов» главы 3.)
(o) Функции (или процедуры) ядраПодпрограммы внутри операционной системы Windows, которые можно вызывать только в режиме ядра (определение мы дадим чуть позже). Например,
ExAllocatePool -процедура, вызываемая драйверами устройств для выделения памяти из системных куч (динамически распределяемых областей памяти) Windows.
(o) Windows-сервисыПроцессы, запускаемые диспетчером управления сервисами в Windows. (Хотя в документации на реестр драйверы устройств Windows определяются как сервисы, мы не пользуемся таким термином в этой книге.) Например, сервис Task Scheduler выполняется в процессе пользовательского режима, который поддерживает команду
at(аналогичную UNIX-команде
atили
cron).
(o) DLL (динамически подключаемая библиотека)Набор вызываемых подпрограмм, включенных в один двоичный файл, который приложения, использующие эти подпрограммы, могут динамически загружать во время своего выполнения. B качестве примера можно привести модули Msvcrt.dll (библиотека исполняющей подсистемы C) и Kernel32.dll (одна из библиотек подсистемы Windows API). DLL активно используются компонентами и приложениями Windows пользовательского режима. Преимущество DLL над статическими библиотеками в том, что приложения могут разделять DLL-модули, a Windows гарантирует, что в памяти будет находиться лишь по одному экземпляру используемых DLL.
Процессы, потоки и задания
Хотя на первый взгляд кажется, что
программаи
процесс- понятия практически одинаковые, они фундаментально отличаются друг от друга.
Программапредставляет собой статический набор команд, а
процесс -это контейнер для набора ресурсов, используемых при выполнении экземпляра
программы. Ha самом высоком уровне абстракции процесс в Windows включает следующее:
(o)закрытое
виртуальное адресное пространство -диапазон адресов виртуальной памяти, которым может пользоваться процесс;
(o)исполняемую программу - начальный код и данные, проецируемые на виртуальное адресное пространство процесса;
(o)список открытых описателей (handles) различных системных ресурсов - семафоров, коммуникационных портов, файлов и других объектов, доступных всем потокам в данном процессе;
(o)контекст защиты (security context), называемый
маркером доступа(access token) и идентифицирующий пользователя, группы безопасности и привилегии, сопоставленные с процессом;
(o)уникальный идентификатор процесса (во внутрисистемной терминологии называемый идентификатором клиента);
(o)минимум один поток.
Каждый процесс также указывает на свой родительский процесс (процесс-создатель). Однако, если родитель существует, эта информация не обновляется. Поэтому есть вероятность, что некий процесс указывает на уже несуществующего родителя. Это не создает никакой проблемы, поскольку никто не полагается на наличие такой информации. Следующий эксперимент иллюстрирует данный случай.
ЭКСПЕРИМЕНТ: просмотр дерева процессов
Большинство утилит не отображает такой уникальный атрибут, как идентификатор родительского процесса. Значение этого атрибута можно получить программно или с помощью оснастки Performance, запросив значение счетчика Creating Process ID [Код (ID) создавшего процесса]. Дерево процессов показывается утилитой Tlist.exe (из Windows Debugging Tools), если вы указываете ключ /t. Вот образец вывода этой команды:
Взаимоотношения процессов (дочерний-родительский) Tlist показывает отступами. Имена процессов, родительские процессы которых на данный момент завершились, выравниваются по левому краю, потому что установить их родственные связи невозможно - даже если процессы-прапредки еще существуют. Windows сохраняет идентификатор только родительского процесса, так что проследить его создателя нельзя. Чтобы убедиться в этом, выполните следующие операции.
1. Откройте окно командной строки.
2. Наберите
start cmdдля запуска второго окна командной строки.
3. Откройте диспетчер задач.
4. Переключитесь на второе окно командной строки.
5. Введите
mspaintдля запуска Microsoft Paint.
6. Щелкните второе окно командной строки.
7. Введите
exit.(Заметьте, что окно Paint остается.)
8. Переключитесь в диспетчер задач.
9. Откройте его вкладку Applications (Приложения). Ю.Щелкните правой кнопкой мыши задачу Command Prompt (Командная строка) и выберите Go To Process (Перейти к процессам).
11.Щелкните процесс Cmd.exe, выделенный серым цветом.
12.Щелкнув правой кнопкой мыши, выберите команду End Process Tree
(Завершить дерево процессов).
13.B окне Task Manager Warning (Предупреждение диспетчера задач) щелкните
Yes(Да).
Первое окно командной строки исчезнет, но вы по-прежнему сможете наблюдать окно Paint, так как оно является внуком первого из завершенных процессов Command Prompt. A поскольку второй (родительский процесс Paint) тоже завершен, связь между родителем и внуком потеряна.
Для просмотра (и модификации) процессов и информации, связанной с ними, существует целый набор утилит. Следующие эксперименты демонстрируют, как получить ту или иную информацию о процессе с помощью некоторых из этих утилит. Они включаются непосредственно в саму Windows, а также в Windows Support Tools, Windows Debugging Tools, ресурсы Windows и Platform SDK
.Многие из этих утилит выводят перекрывающиеся подмножества информации о базовых процессах и потоках, иногда идентифицируемые по разным именам.
Вероятно, наиболее широко применяемая утилита для анализа активности процессов - Task Manager (Диспетчер задач). (Любопытно, что в ядре Windows нет такого понятия, как задача, так что Task Manager на самом деле является инструментом для управления процессами.) Следующий эксперимент показывает разницу между тем, что Task Manager перечисляет как приложения и процессы.
ЭКСПЕРИМЕНТ: просмотр информации о процессах через диспетчер задач
Диспетчер задач Windows отображает список выполняемых в системе процессов. Его можно запустить тремя способами: 1) нажав клавиши Ctrl+Shift+Esc; 2) щелкнув панель задач правой кнопкой мыши и выбрав команду Task Manager (Диспетчер задач); 3) нажав клавиши Ctrl+Alt+Del. После запуска диспетчера задач откройте вкладку Processes (Процессы). Заметьте, что процессы идентифицируются по имени образа, экземплярами которого они являются. B отличие от некоторых объектов в Windows процессам нельзя присваивать глобальные имена. Для просмотра более подробных сведений выберите из меню View (Вид) команду Select Columns (Выбрать столбцы) и укажите, какая дополнительная информация вас интересует.
Если вкладка Processes окна диспетчера задач со всей очевидностью показывает список процессов, то содержимое вкладки Applications (Приложения) нуждается в пояснениях. Ha ней отображается список видимых окон верхнего уровня всех объектов «рабочий стол» интерактивного объекта WindowStation. (По умолчанию существуют два объекта «рабочий стол», но вы можете создать дополнительные рабочие столы через Windows-функцию
CreateDesktop.)Колонка Status (Состояние) дает представление о том, находится ли поток - владелец окна в состоянии ожидания Windows-сообщения. «Running» («Выполняется») означает, что поток ожидает ввода в окно, a «Not Responding» («He
отвечает») - что не ожидает (т. е. занят либо ждет завершения операции ввода-вывода или освобождения какого-либо синхронизирующего объекта).
Вкладка Applications позволяет идентифицировать процесс, которому принадлежит поток, владеющий каким-либо окном задачи. Для этого щелкните правой кнопкой мыши имя задачи и выберите команду Go To Process (Перейти к процессам).
Утилита Process Explorer показывает больше информации о процессах и потоках, чем любой другой доступный инструмент; вот почему она используется нами во многих экспериментах, которые вы увидите в этой книге. Ниже перечислены некоторые уникальные сведения, выводимые утилитой Process Explorer, и ее возможности:
(o)полное имя (вместе с путем) выполняемого образа;
(o)маркер защиты процесса (список групп и привилегий);
(o)выделение изменений в списке процессов и потоков;
(o)список сервисов внутри процессов - хостов сервисов с выводом отображаемого имени (display name) и описания;
(o)процессы, которые являются частью задания, и детальные сведения о заданиях;
(o)процессы, выполняющие .NET/WinFX-приложения, и сведения, специфичные для .NET (например, список доменов приложений и счетчики производительности, относящиеся к CLR);
(o)время запуска процессов и потоков;
(o)полный список файлов, проецируемых в память (не только DLL-модулей);
(o)возможность приостановки процесса;
(o)возможность принудительного завершения индивидуальных потоков;
(o)простота выявления процессов, использующих наибольшую долю процессорного времени за определенный период. (Оснастка Performance позволяет просматривать процент использования процессора для заданного набора процессов, но не показывает автоматически процессы, созданные после начала сеанса мониторинга.)
Process Explorer также упрощает доступ к информации, предоставляемой другими утилитами, создавая единую точку ее просмотра:
(o)дерево процессов с возможностью свертывания отдельных частей этого дерева;
(o)открытые описатели в процессе без предварительной настройки (утилиты Microsoft для вывода открытых описателей требуют предварительной установки общесистемного флага и перезагрузки);
(o)список DLL (и файлов, проецируемых в память) в каком-либо процессе;
(o)активность потоков в каком-либо процессе;
(o)стеки потоков пользовательского режима (с сопоставлением адресов именам, используя механизм поддержки символов для инструментов отладки);
(o)стеки системных потоков режима ядра (с сопоставлением адресов именам, используя механизм поддержки символов для инструментов отладки);
(o)разница в переключении контекстов (context switch delta) (более наглядное представление активности процессора, как поясняется в главе 6);
(o)лимиты памяти режима ядра (пулов подкачиваемой и неподкачиваемой памяти) (остальные утилиты показывают только текущие размеры). Попробуем провести первый эксперимент с помощью Process Explorer.
ЭКСПЕРИМЕНТ: просмотр детальных сведений о процессах с помощью Process Explorer
Скачайте последнюю версию Process Explorer и запустите ее. При первом запуске вы увидите сообщение о том, что на данный момент символы не сконфигурированы. Когда они корректно сконфигурированы, Process Explorer может обращаться к символьной информации для отображения символьного имени стартовой функции потока и функций в его стеке вызовов (для этого нужно дважды щелкнуть процесс и выбрать вкладку Threads). Эта информация полезна для идентификации того, что именно делают потоки внутри процесса. Для доступа к символам вы должны установить Debugging Tools (об этом мы еще поговорим в данной главе). Потом щелкнуть Options, выбрать Configure Symbols и набрать подходящий путь Symbols. Например:
B предыдущем примере для доступа к символам использовался сервер символов по требованию (on-demand symbol server), а копии файлов символов хранились на локальном компьютере в папке
. Подробнее о конфигурировании сервера символов см. по ссылке h
ttp:/
. При запуске Process Explorer по умолчанию выводит список процессов в верхней половине окна, а список открытых описателей для выбранного на данный момент процесса - в нижней половине. Если вы задержите курсор мыши над именем процесса, Process Explorer также показывает описание образа, название компании и полный путь.
Вот как использовать некоторые базовые возможности Process Explorer:
1. Отключите нижнюю секцию, сбросив View, Show Lower Pane. (Нижняя секция может отображать открытые описатели или проецируемые DLL и файлы - об этом речь пойдет в главах 3 и 7.)
2. Обратите внимание на то, что процессы, являющиеся хостами сервисов, по умолчанию выделяются розовым цветом. Ваши собственные процессы выделяются синим. (Эти цвета можно настроить.)
3. Задержите курсор мыши над именем образа и обратите внимание на то, что в подсказке отображается полный путь.
4. Щелкните View, Select Columns и добавьте путь образа.
5. Отсортируйте по колонке процессов и вы увидите, что представление в виде дерева исчезло. (Вы можете либо вывести представление в виде дерева, либо сортировать по любой из отображаемых колонок.) Снова щелкните для сортировки по алфавиту в обратном порядке (от Z к А). После этого очередной щелчок вернет представление в виде дерева.
6. Сбросьте View, Show Processes From All Users для отображения только ваших процессов.
7. Перейдите в Options, Difference Highlight Duration и смените значение на 5 секунд. Потом запустите новый процесс (какой угодно) и обратите внимание на то, что этот процесс выделяется зеленым в течение 5 секунд. Закройте новый процесс и заметьте, что этот процесс выделяется красным в течение 5 секунд, прежде чем исчезнуть из древовидного списка. Эта функция может пригодиться для обнаружения создаваемых и завершаемых процессов в системе.
8. Наконец, дважды щелкните какой-нибудь процесс и изучите вкладки, доступные в окне свойств процесса. (Эти вкладки понадобятся нам в дальнейших экспериментах; там же мы поясним, какую информацию они сообщают.)
Поток(thread) - некая сущность внутри процесса, получающая процессорное время для выполнения. Без потока программа процесса не может выполняться. Поток включает следующие наиболее важные элементы:
(o)содержимое набора регистров процессора, отражающих состояние процессора;
(o)два стека, один из которых используется потоком при выполнении в режиме ядра, а другой - в пользовательском режиме;
(o)закрытую область памяти, называемую локальной памятью потока (thread-local storage, TLS) и используемую подсистемами, библиотеками исполняющих систем (run-time libraries) и DLL;
(o)уникальный идентификатор потока (во внутрисистемной терминологии также называемый идентификатором клиента: идентификаторы процессов и потоков генерируются из одного пространства имен и никогда не перекрываются);
(o)иногда потоки обладают своим контекстом защиты, который обычно используется многопоточными серверными приложениями, подменяющими контекст защиты обслуживаемых клиентов.
Переменные регистры, стеки и локальные области памяти называются
контекстом потока.Поскольку эта информация различна на каждой аппаратной платформе, на которой может работать Windows, соответствующая
структура данных специфична для конкретной платформы. Windows-функция
GetThreadContextпредоставляет доступ к этой аппаратно-зависимой информации (называемой блоком CONTEXT).
Волокна и потоки
Волокна (fibers) позволяют приложениям планировать собственные «потоки» выполнения, не используя встроенный механизм планирования потоков на основе приоритетов. Волокна часто называют «облегченными» потоками. Они невидимы ядру, так как Kernel32.dll реализует их в пользовательском режиме. Для использования волокна нужно вызвать Windows-функцию
ConvertTbreadToFiber,которая преобразует поток в волокно. Полученное волокно может создавать дополнительные волокна через функцию
CreateFiber(у каждого волокна может быть свой набор волокон). Выполнение волокна (в отличие от потока) не начинается до тех пор, пока оно не будет вручную выбрано вызовом
SwitchToFiber.Волокно работает до завершения или до переключения процессора на другое волокно вызовом все той же
SwitcbToFiber.Подробнее о функциях, связанных с волокнами, см. документацию Platform SDK.
Хотя у потоков свой контекст выполнения, каждый поток внутри одного процесса делит его виртуальное адресное пространство (а также остальные ресурсы, принадлежащие процессу). Это означает, что все потоки в процессе могут записывать и считывать содержимое памяти любого из потоков данного процесса. Однако потоки не могут случайно сослаться на адресное пространство другого процесса. Исключение возможно в ситуации, когда тот предоставляет часть своего адресного пространства как
раздел общей памяти(shared memory section), в Windows API называемый объектом «проекция файла» (file mapping object), или когда один из процессов имеет право на открытие другого процесса и использует функции доступа к памяти между процессами, например
ReadProcessMemoryи
WriteProcessMemory. Кроме закрытого адресного пространства и одного или нескольких потоков у каждого процесса имеются идентификация защиты и список открытых описателей таких объектов, как файлы и разделы общей памяти, или синхронизирующих объектов вроде мьютексов, событий и семафоров (рис. 1-2).
Каждый процесс обладает контекстом защиты, который хранится в объекте
- маркере доступа.Маркер доступа содержит идентификацию защиты и определяет полномочия данного процесса. По умолчанию у потока нет собственного маркера доступа, но он может получить его, и это позволит ему подменять контекст защиты другого процесса (в том числе выполняемого на удаленной системе Windows). Подробнее на эту тему см. главу 8.
Дескрипторы виртуальных адресов (virtual address descriptors, VAD) - это структуры данных, используемые диспетчером памяти для учета виртуальных адресов, задействованных процессом (см. главу 7).
Windows предоставляет расширение для модели процессов -
задания(jobs). Они предназначены в основном для того, чтобы группами процессов можно было оперировать и управлять как единым целым. Объект-задание позволяет устанавливать определенные атрибуты и накладывать ограничения на процесс или процессы, сопоставленные с заданием. B этом объекте также хранится информация обо всех процессах, которые были сопоставлены с заданием, но к настоящему времени уже завершены. B каких-то отношениях объект-задание компенсирует отсутствие иерархического дерева процессов в Windows, а в каких-то - даже превосходит по своим возможностям дерево процессов UNIX.
Более детальное описание внутренней структуры заданий, процессов и потоков, механизмов создания потоков и процессов, а также алгоритмов планирования потоков вы найдете в главе 6.
Виртуальная память
B Windows реализована система виртуальной памяти, основанная на плоском (линейном) адресном пространстве. Она создает каждому процессу иллюзию того, что у него есть собственное большое и закрытое адресное пространство. Виртуальная память дает логическое представление, не обязательно соответствующее структуре физической памяти. B период выполнения диспетчер памяти, используя аппаратную поддержку, транслирует, или
проецирует(maps), виртуальные адреса на физические, по которым реально хранятся данные. Управляя проецированием и защитой страниц памяти, операционная система гарантирует, что ни один процесс не помешает другому и не сможет повредить данные самой операционной системы. Ha рис. 1-3 показано, как три смежные страницы виртуальной памяти проецируются на три разрозненные страницы физической памяти.
Поскольку у большинства компьютеров объем физической памяти намного меньше общего объема виртуальной памяти, задействованной выполняемыми процессами, диспетчер памяти перемещает, или подкачивает (pages), часть содержимого памяти на диск. Подкачка данных на диск освобождает физическую память для других процессов или самой операционной системы. Когда поток обращается к странице виртуальной памяти, сброшенной на диск, диспетчер виртуальной памяти загружает эту информацию с диска обратно в память. Для использования преимуществ подкачки в приложениях никакого дополнительного кода не требуется, так как диспетчер памяти опирается на аппаратную поддержку этого механизма.
Размер виртуального адресного пространства зависит от конкретной аппаратной платформы. Ha 32-разрядных х86-системах теоретический максимум для общего виртуального адресного пространства составляет 4 Гб. По умолчанию Windows выделяет нижнюю половину этого пространства (в диапазоне адресов от x00000000 до x7FFFFFFF) процессам, а вторую половину (в диапазоне адресов от x80000000 до xFFFFFFFF) использует в собственных целях. Windows 2000 Advanced Server, Windows 2000 Datacenter Server, Windows XP (SP2 и выше) и Windows Server 2003 поддерживают загрузочные параметры /3GB и /USERVA, которые указываются в файле Boot.ini (см. главу 5), что позволяет процессам, выполняющим программы со специальным флагом в заголовке исполняемого образа, использовать до 3 Гб закрытого адресного пространства и оставляет операционной системе только 1 Гб. Этот вариант дает возможность приложению вроде сервера базы данных хранить в адресном пространстве своего процесса большие порции базы данных и тем самым уменьшить частоту проецирования отдельных представлений этой базы. Две структуры виртуальных адресных пространств, поддерживаемые 32-разрядной Windows, показаны на рис. 1-4.
Хотя три гигабайта лучше двух, этого все равно недостаточно для проецирования очень больших баз данных. B связи с этим в 32-разрядных Windows появился механизм Address Windowing Extension (AWE), который позволяет 32-разрядному приложению выделять до 64 Гб физической памяти, а затем проецировать представления (views), или окна (windows), на свое 2-гигабайтное виртуальное адресное пространство. Применение AWE усложняет управление проекциями виртуальной памяти на физическую, но снимает проблему прямого доступа к объему физической памяти, превышающему лимиты 32-разрядного адресного пространства процесса.
64-разрядная Windows предоставляет процессам гораздо большее адресное пространство: 7152 Гб на Itanium-системах и 8192 Гб на х64-системах. Ha рис. 1-5 показана упрощенная схема структур 64-разрядных адресных пространств (детали см. в главе 7). Заметьте, что эти размеры отражают не архитектурные лимиты для данных платформ, а ограничения реализации в текущих версиях 64-разрядной Windows.
Подробнее о реализации диспетчера памяти, в том числе о трансляции адресов и управлении физической памятью в Windows, см. главу 7.
Режим ядра и пользовательский режим
Для предотвращения доступа приложений к критически важным данным операционной системы и устранения риска их модификации Windows использует два режима доступа к процессору (даже если он поддерживает более двух режимов): пользовательский (user mode) и ядра (kernel mode). Код
приложений работает в пользовательском режиме, тогда как код операционной системы (например, системные сервисы и драйверы устройств) - в режиме ядра. B режиме ядра предоставляется доступ ко всей системной памяти и разрешается выполнять любые машинные команды процессора. Предоставляя операционной системе более высокий уровень привилегий, чем прикладным программам, процессор позволяет разработчикам операционных систем реализовать такие архитектуры, которые не дают возможности сбойным приложениям нарушать стабильность работы всей системы.
ПРИМЕЧАНИЕ
B архитектуре процессора Intel x86 определено четыре уровня привилегий, или колец (rings), предназначенных для защиты кода и данных системы от случайной или умышленной перезаписи кодом с меньшим уровнем привилегий. Windows использует уровень привилегий 0 (или кольцо 0) для режима ядра и уровень привилегий 3 (или кольцо 3) для пользовательского режима. Почему Windows использует только два уровня? Дело в том, что на некоторых из ранее поддерживавшихся аппаратных платформ (например, Compaq Alpha и Silicon Graphics MIPS) реализовано лишь два уровня привилегий.
Хотя каждый Windows-процесс имеет свою (закрытую) память, код операционной системы и драйверы устройств, работающие в режиме ядра, делят единое виртуальное адресное пространство. Каждая страница в виртуальной памяти помечается тэгом, определяющим, в каком режиме должен работать процессор для чтения и/или записи данной страницы. Страницы в системном пространстве доступны лишь в режиме ядра, а все страницы в пользовательском адресном пространстве - в пользовательском режиме. Страницы только для чтения (например, содержащие лишь исполняемый код) ни в каком режиме для записи недоступны.
Windows не предусматривает никакой защиты системной памяти от компонентов, работающих в режиме ядра. Иначе говоря, код операционной системы и драйверов устройств в режиме ядра получает полный доступ к системной памяти и может обходить средства защиты Windows для обращения к любым объектам. Поскольку основная часть кода Windows выполняется в режиме ядра, крайне важно, чтобы компоненты, работающие в этом режиме, были тщательно продуманы и протестированы.
Это также подчеркивает, насколько надо быть осторожным при загрузке драйвера устройства от стороннего поставщика: перейдя в режим ядра, он получит полный доступ ко всем данным операционной системы. Такая уязвимость стала одной из причин, по которым в Windows введен механизм проверки цифровых подписей драйверов, предупреждающий пользователя о попытке установки неавторизованного (неподписанного) драйвера (подробнее на эту тему см. главу 9). Кроме того, механизм Driver Verifier (верификатор драйверов) помогает разработчикам драйверов устройств находить в них ошибки (вызывающие, например, утечку памяти или переполнения буферов). Driver Verifier поясняется в главе 7.
Как вы увидите в главе 2, прикладные программы могут переключаться из пользовательского режима в режим ядра, обращаясь к системному сервису. Например, Windows-функции
ReadFileв ходе своего выполнения приходится вызывать внутреннюю подпрограмму Windows - она-то и считывает данные из файла. Так как эта подпрограмма обращается к внутрисистемным структурам данных, она должна выполняться в режиме ядра. Переключение из пользовательского режима в режим ядра осуществляется специальной командой процессора. Операционная система перехватывает эту команду, обнаруживает запрос системного сервиса, проверяет аргументы, которые поток передал системной функции, и выполняет внутреннюю подпрограмму. Перед возвратом управления пользовательскому потоку процессор переключается обратно в пользовательский режим. Благодаря этому операционная система защищает себя и свои данные от возможной модификации пользовательскими процессами.
ПРИМЕЧАНИЕ
Переключение из пользовательского режима в режим ядра (и обратно) не влияет на планирование потока, так как контекст в этом случае не переключается. O диспетчеризации системных сервисов см. главу 3.
Так что ситуация, когда пользовательский поток часть своего времени работает в пользовательском режиме, а часть - в режиме ядра, совершенно нормальна. A поскольку подсистема, отвечающая за поддержку графики и окон, функционирует в режиме ядра, то приложения, интенсивно работающие с графикой, большую часть времени действуют в режиме ядра, а не в пользовательском режиме. Самый простой способ проверить это - запустить приложение вроде Microsoft Paint или Microsoft Pinball и с помощью одного из счетчиков оснастки Performance (Производительность), перечисленных в таблице 1-2, понаблюдать за показателями времени работы в пользовательском режиме и в режиме ядра.
ЭКСПЕРИМЕНТ: наблюдение за активностью потоков с помощью QuickSlice
QuickSlice позволяет в динамике наблюдать за соотношением времени, проведенного каждым процессом в режиме ядра и в пользовательском режиме. Ha диаграмме красная часть столбца отражает количество процессорного времени в режиме ядра, а синяя - в пользовательском режиме. (Хотя в книге эти столбцы воспроизведены в черно-белом цвете, на самом деле они всегда красные и синие.) Сумма всех показателей, отображаемых столбцами в окне QuickSlice, должна соответствовать 100% процессорного времени. Для запуска QuickSlice щелкните кнопку Start (Пуск), выберите команду Run (Выполнить) и введите
Qslice.exe(в переменной PATH должен быть указан путь к ресурсам Windows). Например, попробуйте запустить такое интенсивно использующее графику приложение, как Paint (Mspaint.exe). Откройте QuickSlice, расположив его окно рядом с окном Paint, и нарисуйте в Paint несколько кривых. B это время вы сможете наблюдать за выполнением Mspaint.exe в окне QuickSlice, как показано ниже.
Чтобы получить дополнительную информацию о потоках процесса, дважды щелкните имя нужного процесса или соответствующий цветной столбик на диаграмме. Вы увидите список потоков этого процесса и относительное процессорное время, используемое каждым потоком (в рамках процесса, а не всей системы).
ЭКСПЕРИМЕНТ: режим ядра и пользовательский режим
C помощью оснастки Performance вы можете выяснить, сколько времени ваша система работает в режиме ядра и в пользовательском режиме.
1. Запустите оснастку Performance (Производительность), открыв меню Start (Пуск) и последовательно выбрав команды Programs (Программы), Administrative Tools (Администрирование), Performance (Производительность).
2. Щелкните на панели инструментов кнопку Add (Добавить) (на этой кнопке изображен большой знак плюс).
3. Выберите в списке объект Processor (Процессор), щелкните счетчик % Privileged Time (% работы в привилегированном режиме) и, удерживая клавишу Ctrl в нажатом состоянии, щелкните счетчик % User Time (% работы в пользовательском режиме).
4. Щелкните кнопку Add (Добавить), а затем Close (Закрыть).
5. Быстро подвигайте мышью. При этом вы должны заметить всплеск на линии % Privileged Time (рис. 1-6), который отражает время, затраченное на обслуживание прерываний от мыши, и время, понадобившееся подсистеме поддержки окон на отрисовку графики (эта подсистема, как поясняется в главе 2, работает преимущественно как драйвер устройства в режиме ядра).
6. Закончив, щелкните на панели инструментов кнопку New Counter Set (Новый набор счетчиков) (или просто закройте оснастку).
За той же активностью можно понаблюдать через Task Manager (Диспетчер задач). Просто перейдите в нем на вкладку Performance (Быстродействие), а затем выберите из меню View (Вид) команду Show Kernel Times (Вывод времени ядра). Процент загруженности процессора отражается зеленым цветом, а процент времени работы в режиме ядра - красным.
Чтобы увидеть, как сама оснастка Performance использует время в двух режимах, запустите ее снова, но добавьте те же счетчики для объекта Process (Процесс).
1. Если вы закрыли оснастку Performance, снова запустите ее. (Если она уже работает, откройте новый экран, щелкнув на панели инструментов кнопку New Counter Set.)
2. Щелкните кнопку Add на панели инструментов.
3. Выберите в списке объект Process.
4. Выберите счетчики % Privileged Time и % User Time.
5. B списке экземпляров объекта выберите все процессы (кроме процесса _Total).
6. Щелкните кнопку Add, а затем Close.
7. Быстро подвигайте мышью.
8. Нажмите комбинацию клавиш Ctrl+H для активизации режима выделения - текущий выбранный счетчик будет выделен белым цветом в Windows 2000 и черным в Windows XP или Windows Server 2003.
9. Прокрутите список всех счетчиков в нижней части окна оснастки, чтобы определить процессы, потоки которых выполнялись при перемещении мыши, и обратите внимание на то, в каком режиме они выполнялись - пользовательском или ядра.
Вы должны заметить, как значения счетчиков для процесса оснастки Performance - ищите mmc в колонке Instance (Экземпляр) - резко увеличиваются при перемещении мыши, поскольку код приложения выполняется в пользовательском режиме, а вызываемые им Windows-функции - в режиме ядра. Вы также заметите, что при перемещении мыши увеличивается активность работы в режиме ядра потока процесса csrss. Он представляет поток необработанного ввода (raw input thread) подсистемы Windows, принимающий ввод от клавиатуры и мыши и передающий его процессу, к которому он подключен. (Подробнее о системных потоках см. главу 2.) Наконец, процесс с именем Idle, потоки которого, как вы убедитесь, тратят почти 100% своего времени в режиме ядра, на самом деле не является процессом. Это лжепроцесс, используемый для учета тактов процессора в состоянии простоя. Таким образом, когда Windows нечего делать, она предается этому занятию в режиме ядра.
Terminal Services и несколько сеансов
Terminal Services (службы терминала) обеспечивают в Windows поддержку нескольких интерактивных сеансов пользователей на одной системе. C помощью Terminal Services удаленный пользователь может установить сеанс на другой машине, зарегистрироваться на ней и запускать приложения на сервере. Сервер предоставляет клиенту графический пользовательский интерфейс (GUI), а клиент возвращает серверу пользовательский ввод. (Это отличается от того, как ведет себя X Windows на UNIX-системах, где разрешается выполнять индивидуальные приложения на сервере, а клиенту предоставляется удаленный дисплей, так как удаленным является весь сеанс пользователя - не только одно приложение.)
Первый сеанс входа на физической консоли компьютера считается консольным сеансом, или нулевым сеансом (session zero). Дополнительные сеансы можно создать с помощью программы соединения с удаленным рабочим столом (Mstsc.exe), а в Windows XP - через механизм быстрого переключения пользователей (об этом позже).
Возможность создания удаленного сеанса поддерживается Windows 2000 Server, но не Windows 2000 Professional. Windows XP Professional позволяет одному удаленному пользователю подключаться к машине, однако если кто-то начинает процедуру входа в консоли, рабочая станция блокируется (т. е. систему можно использовать либо локально, либо удаленно, но не и то, и другое одновременно).
Windows 2000 Server и Windows Server 2003 поддерживают два одновременных удаленных сеанса. (Это упрощает удаленное управление, например облегчает применение инструментов, требующих от администратора входа на удаленный компьютер.) Windows 2000 Advanced Server, Datacenter Server и все издания Windows Server 2003 способны поддерживать более двух сеансов одновременно при условии правильного лицензирования и настройки системы в качестве сервера терминала.
Хотя Windows XP Home и Professional не поддерживают несколько удаленных подключений к рабочему столу, они все же поддерживают несколько сеансов, созданных локально через механизм быстрого переключения пользователей. (Этот механизм отключается в Windows XP Professional, если система присоединяется к домену.) Когда пользователь выбирает выключение своего сеанса вместо выхода [например, последовательным выбором Start (Пуск), Log Off (Выход из системы) и Switch User (Смена пользователя) или нажатием клавиши L при одновременном удерживании клавиши Windows], текущий сеанс (т. е. процессы, выполняемые в этом сеансе, и все структуры данных, глобальные для сеанса и описывающие его) остается в системе, а Windows возвращается к основному окну входа. Если в систему входит новый пользователь, создается новый сеанс.
Для приложений, которым нужно знать, выполняются ли они в сеансе сервера терминала, предназначен набор Windows API-функций, позволяющих программно распознавать такую ситуацию и контролировать различные аспекты служб терминала. (Детали см. в Platform SDK.)
B главе 2 кратко описывается, как создаются сеансы, и проводится несколько экспериментов, показывающих, как просматривать информацию о сеансе с помощью различных инструментов, включая отладчик ядра. B разделе «Диспетчер объектов» главы 3 поясняется, как создается сеансовый экземпляр системного пространства имен для объектов и как приложения могут узнавать о других своих экземплярах в той же системе. Наконец, в главе 7 рассказывается, как диспетчер памяти настраивает данные, глобальные для сеанса, и управляет ими.
Объекты и описатели
B операционной системе Windows
объект -это единственный экземпляр периода выполнения (run-time instance) статически определенного типа объекта.
Тип объектасостоит из общесистемного типа данных, функций, оперирующих экземплярами этого типа данных, и набора атрибутов. Если вы пишете Windows-приложения, вам наверняка знакомы такие объекты, как процесс, поток, файл и событие, - продолжать можно еще долго. Эти объекты базируются на объектах более низкого уровня, создаваемых и управляемых Windows. B Windows процесс является экземпляром объекта типа «процесс», файл - экземпляром объекта типа «файл» и т. д.
Атрибут объекта(object attribute) - это поле данных в объекте, частично определяющее состояние этого объекта. Например, объект типа «процесс», имеет атрибуты, в число которых входят идентификатор процесса, базовый приоритет и указатель на объект маркера доступа. Методы объекта (средства для манипулирования объектами) обычно считывают или изменяют какие-либо атрибуты. Так, метод
openпроцесса мог бы принимать идентификатор процесса и возвращать указатель на этот объект.
ПРИМЕЧАНИЕ
He путайте параметр ObjectAttributes, предоставляемый вызывающей программой при создании объекта через Windows API или его родные сервисы, с термином «атрибуты объекта», имеющим более общий смысл.
Самое главное различие между объектом и обычной структурой данных заключается в том, что внутренняя структура объекта скрыта. Чтобы получить данные из объекта или записать в него какую-то информацию, вы долж-
ны вызвать его сервис. Прямое чтение или изменение данных внутри объекта невозможно. Тем самым реализация объекта отделяется от кода, который просто использует его, а это позволяет менять реализацию объекта, не модифицируя остальной код.
Объекты очень удобны для поддержки четырех важных функций операционной системы:
(o)присвоения понятных имен системным ресурсам;
(o)разделения ресурсов и данных между процессами;
(o)защиты ресурсов от несанкционированного доступа;
(o)учета ссылок (благодаря этому система узнает, когда объект больше не используется, и автоматически уничтожает его).
He все структуры данных в Windows являются объектами. B объекты помещаются лишь те данные, которые нужно разделять, защищать, именовать или делать доступными программам пользовательского режима (через системные сервисы). Структуры, используемые только одним из компонентов операционной системы для поддержки каких-то внутренних функций, к объектам не относятся. Подробнее объекты и их описатели (ссылки на экземпляр объекта) рассматриваются в главе 3.
Безопасность
Windows с самого начала разрабатывалась как защищенная система, удовлетворяющая требованиям различных правительственных и промышленных стандартов безопасности, например спецификации Common Criteria for Information Technology Security Evaluation (CCITSE). Подтверждение правительством рейтинга безопасности операционной системы позволяет ей конкурировать в сферах, требующих повышенной защиты. Разумеется, многим из этих требований должна удовлетворять любая многопользовательская система.
Базовые возможности защиты в Windows таковы: избирательная защита любых разделяемых системных объектов (файлов, каталогов, процессов, потоков и т. д.), аудит безопасности (для учета пользователей и инициируемых ими операций), аутентификация паролей при входе и предотвращение доступа одного из пользователей к неинициализированным ресурсам (например, к памяти или дисковому пространству), освобожденным другим пользователем.
Windows поддерживает два вида контроля доступа к объектам. Первый из них -
управление избирательным доступом(discretionary access control) - является механизмом, который как раз и связывается большинством пользователей с защитой. Это метод, при котором владельцы объектов (например, файлов или принтеров) разрешают или запрещают доступ к ним для других пользователей. При входе пользователь получает набор удостоверений защиты (security credentials), или контекст защиты (security context). Когда он пытается обратиться к объекту, его контекст защиты сверяется со списком управления доступом (access control list, ACL) для данного объекта, чтобы определить, имеет ли он разрешение на выполнение запрошенной операции.
Второй метод
-управление привилегированным доступомQ3riv1leged access control) - необходим в тех случаях, когда управления избирательным доступом недостаточно. Данный метод гарантирует, что пользователь сможет обратиться к защищенным объектам, даже если их владелец недоступен. Например, если какой-то сотрудник увольняется из компании, администратору нужно получить доступ к файлам, которые могли быть доступны только бывшему сотруднику. B таких случаях Windows позволяет администратору стать владельцем этих файлов и при необходимости управлять правами доступа к ним.
Защита пронизывает весь интерфейс Windows APL Подсистема Windows реализует защиту на основе объектов точно так же, как и сама операционная система. При первой попытке доступа приложения к общему (разделяемому) объекту подсистема Windows проверяет, имеет ли это приложение соответствующие права. Если проверка завершается успешно, подсистема Windows разрешает приложению доступ.
Подсистема Windows реализует защиту для общих объектов, часть из которых построена на основе родных объектов Windows. K Windows-объектам относятся объекты рабочего стола, меню, окна, файлы, процессы, потоки и ряд синхронизирующих объектов.
Детальное описание защиты в Windows см. в главе 8.
Реестр
Если вы работали хоть с какой-нибудь операционной системой Windows, то, вероятно, слышали о реестре или даже просматривали его. Рассказать о внутреннем устройстве Windows, не упоминая реестр, вряд ли возможно, так как это системная база данных с информацией, необходимой для загрузки и конфигурирования системы; в ней содержатся общесистемные параметры, контролирующие работу Windows, база данных защиты и конфигурационные настройки, индивидуальные для каждого пользователя.
Кроме того, реестр - это окно, через которое можно заглянуть в переменные системные данные, чтобы, например, выяснить текущее состояние аппаратной части системы (какие драйверы устройств загружены, какие ресурсы они используют и т. д.) или значения счетчиков производительности Windows. Счетчики производительности, которые на самом деле в реестре не хранятся, доступны через функции реестра (см. главу 4).
Хотя у многих пользователей и администраторов Windows никогда не возникает необходимости работать непосредственно с реестром (большую часть параметров можно просматривать или модифицировать с помощью стандартных административных утилит), он все же является источником полезной информации о внутренних структурах данных Windows, так как содержит множество параметров, влияющих на быстродействие и поведение системы. (Будьте крайне осторожны, напрямую изменяя параметры реестра: любые изменения могут отрицательно сказаться на быстродействии или, что гораздо хуже, привести к краху системы.)
Ссылки на различные разделы реестра, относящиеся к описываемым компонентам, будут встречаться на протяжении всей книги. Большинство таких разделов находится в ветви HKEY_LOCAL_MACHINE, которую мы сокращенно называем HKLM. Подробнее о реестре и его внутренней структуре см. главу 4.
Unicode
Windows отличается от большинства других операционных систем тем, что в качестве внутреннего формата для хранения и обработки текстовых строк использует Unicode. Unicode - это стандартная кодировка, которая поддерживает многие известные в мире наборы символов и в которой каждый символ представляется 16-битным (двухбайтовым) кодом. (Подробнее о Unicode см.
и документацию на компакт-дисках MSDN Library.)
Поскольку многие приложения имеют дело с 8-битными (однобайтовыми) ANSI-символами, Windows-функции, принимающие строковые параметры, существуют в двух версиях: для Unicode и для ANSI. B Windows 95, Windows 98 и Windows ME реализована лишь часть Unicode-версий Windows-функций, поэтому приложения, рассчитанные на выполнение как в одной из этих операционных систем, так и в NT-подобных Windows, обычно используют ANSI-версии функций. Если вы вызываете ANSI-версию Windows-функции, входные строковые параметры перед обработкой системой преобразуются в Unicode, а выходные - из Unicode в ANSI (перед возвратом приложению). Таким образом при использовании в Windows устаревшего сервиса или фрагмента кода, написанного в расчете на ANSI-строки, эта операционная система будет вынуждена преобразовывать ANSI-символы в Unicode. Однако Windows никогда не преобразует данные внутри файлов - решения о том, в какой кодировке хранить текстовую информацию в файлах, принимают лишь сами приложения.
B предыдущих версиях Windows ее азиатский и ближневосточный выпуски представляли собой надмножество базовых американского и европейского выпусков, в которые включались дополнительные Windows-функции для обработки более сложных раскладок клавиатур и принципов ввода текста (например, набора текста справа налево). Начиная с Windows 2000, все языковые выпуски содержат одинаковые Windows-функции. Единая для всех стран двоичная кодовая база Windows способна поддерживать множество языков за счет простого добавления нужных компонентов языковой поддержки. Используя эти Windows-функции, разработчики могут создавать универсальные приложения, способные работать со множеством языков.
Изучение внутреннего устройства Windows
Хотя большая часть информации, представленная в этой книге, получена при чтении исходного кода Windows и общении с разработчиками, вы не обязаны принимать все на веру. Многие детали внутреннего устройства Windows можно вытащить на свет с помощью самых разнообразных средств, в том числе поставляемых с Windows, входящих в Windows Support Tools и ресурсы Windows, а также с использованием отладочных средств самой Windows. Чуть позже мы вкратце рассмотрим эти пакеты инструментальных средств.
Чтобы упростить вам исследование внутреннего устройства Windows, мы часто даем в книге врезки «Эксперимент» с пошаговыми инструкциями для изучения какого-либо аспекта поведения Windows. (Вы уже видели такие врезки в этой главе.) Советуем проводить эти эксперименты - это позволит увидеть в действии многие вещи, о которых рассказывается в книге.
B таблице 1-3 перечислены все используемые нами инструменты и утилиты.
Таблица 1-3.
Средства просмотра внутренней информации Windows
Оснастка Performance
Мы часто ссылаемся на этот инструмент, доступный через папку Administrative Tools (Администрирование) в меню Start (Пуск) или через Control Panel (Панель управления). Оснастка Performance (Производительность) предназначена для мониторинга системы, просмотра журналов, в которых регистрируются значения счетчиков производительности, и оповещения при достижении заданных пороговых значений тех или иных счетчиков. Говоря об оснастке Performance, мы подразумеваем лишь ее функцию системного мониторинга.
Оснастка Performance способна сообщить о том, как работает система, гораздо больше, чем любая другая, отдельно взятая утилита. Она предусматривает сотни счетчиков для различных объектов. По каждому счетчику можно получить краткое описание. Чтобы увидеть описание, выберите счетчик в окне Add Counters (Добавить счетчики) и щелкните кнопку Explain (Объяснение). Или откройте справочный файл Performance Counter Reference с компакт-диска «Ресурсы Windows». Информацию о том, как интерпретировать показания счетчиков для устранения «узких мест» в системе или для планирования пропускной способности сервера, см. раздел «Performance Monitoring» в книге «Windows 2000 Server Operations Guide» из набора Windows 2000 Server Resource Kit. Для Windows XP и Windows Server 2003 см. документацию Performance Counters Reference в Windows Server 2003 Resource Kit.
Заметьте, что все счетчики производительности Windows доступны программным путем. Краткое описание соответствующих компонентов см. в разделе «HKEY_PERFORMANCE_DATA» главы 4.
Windows Support Tools
Windows Support Tools включают около 40 утилит, полезных в администрировании систем на базе Windows и устранении неполадок в них. Многие из этих утилит раньше были частью ресурсов Windows NT 4.
Вы можете установить Support Tools, запустив Setup.exe из папки \Support\ Tools в дистрибутиве любого издания Windows. Support Tools одинаковы в Windows 2000 Professional, Server, Advanced Server и Datacenter Server, a для Windows XP, равно как и для Windows Server 2003, существует своя версия Support Tools.
Ресурсы Windows
Ресурсы Windows (Windows Resource Kits) расширяют Support Tools, предлагая дополнительные утилиты для администрирования и поддержки систем. Утилиты Windows Server 2003 Resource Kit можно бесплатно скачать с
(выполните поиск по ключевым словам «resource kit tools»). Их можно установить в Windows XP или Windows Server 2003.
Ресурсы Windows 2000 существуют в двух изданиях: Windows 2000 Professional Resource Kit и Windows 2000 Server Resource Kit* (самая последняя
Последнее издание переведено на русский язык издательством «Русская Редакция» и выпущено в 2001 г. в виде серии «Ресурсы Microsoft Windows 2000 Server» которая включает 4 книги: «Сети TCP/IP», «Сопровождение сервера», «Распределенные системы» и «Межсетевое взаимодействие». -
Прим. перев. его версия - Supplement 1). Хотя последний набор представляет собой надмножество первого и может быть установлен на системах с Windows 2000 Professional, утилиты, входящие только в Windows 2000 Server Resource Kit, ни в одном из наших экспериментов не используются. B отличие от утилит Windows Server 2003 Resource Kit эти утилиты нельзя скачать бесплатно. Однако Windows 2000 Server Resource Kit поставляется с подписками на MSDN и TechNet.
Отладка ядра
Отладка ядра подразумевает изучение внутренних структур данных ядра и/ или пошаговый проход по функциям в ядре. Это полезный способ исследования внутреннего устройства Windows, потому что он позволяет увидеть внутрисистемную информацию, недоступную при использовании каких-либо других способов, и получить более ясное представление о схеме выполнения кода внутри ядра.
Отладку ядра можно проводить с помощью разнообразных утилит: Windows Debugging Tools от Microsoft, LiveKD от
или SoftIce от Compuware NuMega. Прежде чем описывать эти средства, давайте рассмотрим файл, который понадобится при любом виде отладки ядра.
Символы для отладки ядра
Файлы символов (symbol files) содержат имена функций и переменных. Они генерируются компоновщиком (linker) и используются отладчиками для ссылки и отображения этих имен в сеансе отладки. Эта информация обычно не хранится в двоичном образе, потому что она не нужна при выполнении кода. To есть двоичные образы имеют меньший размер и работают быстрее. Ho это означает, что вам нужно позаботиться о том, чтобы у отладчика был доступ к файлам символов, сопоставляемым с образами, на которые вы ссылаетесь в сеансе отладки.
Для изучения внутренних структур данных ядра Windows (например, списка процессов, блоков потока, списка загруженных драйверов, информации об использовании памяти и т. д.) вам понадобятся подходящие файлы символов как минимум для образа ядра, Ntoskrnl.exe. (Подробнее этот файл рассматривается в разделе «Обзор архитектуры» главы 2.) Файлы таблиц символов должны соответствовать версии образа. Так, если вы установили Windows Service Pack или какое-то оперативное исправление, то должны получить обновленные файлы символов хотя бы для образа ядра; иначе возникнет ошибка из-за неправильной контрольной суммы при попытке отладчика ядра загрузить их.
Хотя можно скачать и установить символы для разных версий Windows, обновленные символы для оперативных исправлений доступны не всегда. Самый простой способ получить подходящую версию символов для отладки - обратиться к Microsoft-серверу символов с запросом, в котором используется специальный синтаксис пути к символам, как в отладчике. Например,
следующий путь к символам заставляет средства отладки загружать требуемые символы с Интернет-сервера символов и сохранять локальную копию в папке
:
srv*c:\symbols*
Подробные инструкции о том, как пользоваться сервером символов, см. в справочном файле Debugging Tools или на Web-странице
wwwmicrosoft. com/whdc/ddk/debugging/symbols.mspx.
Windows Debugging Tools
Пакет Windows Debugging Tools содержит дополнительные средства отладки, применяемые в этой книге для исследования внутреннего устройства Windows. Вы найдете их последние версии по ссылке
whdc/ddk/debugging.Эти средства можно использовать для отладки как процессов пользовательского режима, так и ядра (см. следующую врезку).
ПРИМЕЧАНИЕWindows Debugging Tools регулярно обновляются и выпускаются независимо от версий операционной системы Windows, поэтому почаще проверяйте наличие новых версий отладочных средств.
Отладка в пользовательском режиме
Средства отладки можно подключать к процессу пользовательского режима, чтобы исследовать и/или изменять память процесса. Существует два варианта подключения к процессу:
(o) Invasive (инвазивный)Если не указано иное, то, когда вы подключаетесь к выполняемому процессу, Windows-функция DebugAc-tiveProcess устанавливает соединение между отладчиком и отлаживаемым процессом. Это позволяет изучать и/или изменять память процесса, устанавливать точки прерывания (breakpoints) и выполнять другие отладочные действия. B Windows 2000 при завершении отладчика закрывается и отлаживаемый процесс. Однако в Windows XP отладчик можно отключать, не уничтожая целевой процесс.
(o) Noninvasive (неинвазивный)B этом случае отладчик просто открывает процесс через функцию OpenProcess. Он не подключается к процессу как отладчик Это позволяет изучать и/или изменять память целевого процесса, но не дает возможности устанавливать точки прерывания. Преимущество данного варианта в том, что в Windows 2000 можно закрыть отладчик, не завершая целевой процесс.
C помощью отладочных средств также можно открывать файлы дампов процессов пользовательского режима. Что представляют собой эти файлы, поясняется в главе 3 в разделе по диспетчеризации исключений.
Microsoft предлагает отладчики ядра в двух версиях: командной строки (Kd.exe) и с графическим пользовательским интерфейсом p^indbg.exe). Оба
инструмента предоставляют одинаковый набор команд, так что выбор конкретной утилиты определяется сугубо личными пристрастиями. C помощью этих средств вы можете вести отладку ядра в трех режимах.
(o)Откройте файл дампа, полученный в результате краха системы с Windows (подробнее о таких дампах см. главу 14).
(o)Подключитесь к работающей системе и изучите ее состояние (или поставьте точки прерывания, если вы отлаживаете код драйвера устройства). Эта операция требует двух компьютеров - целевого и управляющего. Целевой считается отлаживаемая система, а управляющей - та, в которой выполняется отладчик. Целевая система может быть либо локальной (соединенной с управляющей нуль-модемным кабелем или по IEEE 1394), либо удаленной (соединенной по модему). Вы должны загрузить целевую систему со спецификатором /DEBUG, или нажать при загрузке клавишу F8 и выбрать Debug Mode, или добавить соответствующую запись в файл Boot.ini.
(o)B случае Windows XP и Windows Server 2003 подключитесь к локальной системе и изучите ее состояние. Это называется
локальной отладкой ядра.Чтобы инициировать такую отладку ядра, выберите в меню FiIe команду Kernel Debug, перейдите на вкладку Local и щелкните ОК. Пример окна с выводом показан на рис. 1-7. Некоторые команды отладчика ядра в этом режиме не работают (например, просмотр стеков ядра и создание дампа памяти командой .dump невозможны). Однако вы можете пользоваться бесплатной утилитой LiveKd с сайта
в тех случаях, когда родные средства локальной отладки не срабатывают (см. следующий раздел).
Подключившись в режиме отладки ядра, вы можете использовать одну из многих команд расширения отладчика (команды, которые начинаются с «!») для вывода содержимого внутренних структур данных, например потоков, процессов, пакетов запроса на ввод-вывод и информации, связанной с управлением памятью. Команды отладчика ядра и их вывод будут обсуждаться при рассмотрении соответствующей тематики. A пока добавим, что команда
dt(display type) может форматировать свыше 400 структур ядра благодаря тому, что файлы символов ядра для Windows 2000 Service Pack 3, Windows XP и Windows Server 2003 содержат информацию о типах, которая и позволяет отладчику форматировать структуры.
ЭКСПЕРИМЕНТ: отображение информации о типах для структур ядра
Чтобы вывести список структур ядра, чья информация о типах включена в символы ядра, наберите
dt nt!_*в отладчике ядра. Пример части вывода показан ниже:
Команда
dtпозволяет искать конкретные структуры по шаблонам. Например, если вы ищете имя структуры для объекта прерывания (interrupt object), введите
dt nt!*interrupt*:
Заметьте, что по умолчанию
dtне показывает подструктуры (структуры внутри структур). Для рекурсивного прохода по подструктурам, используйте ключ
-r.Например, указав этот ключ для отображения объекта ядра «прерывание», вы увидите формат структуры _LIST_ENTRY, хранящейся в поле InterruptListEntry:
B справочном файле Windows Debugging Tools объясняется, как устанавливать и использовать отладчики ядра. Дополнительные сведения о применении отладчиков ядра, предназначенных в основном разработчикам драйверов устройств, см. в документации Windows DDK. Есть также несколько полезных статей в Knowledge Base по отладчикам ядра. Выполните поиск по ключевому слову «debugref» в Windows Knowledge Base (онлайновой базе данных технических статей) на
.
Утилита LiveKd
LiveKd - бесплатная утилита
,которая позволяет использовать стандартные отладчики ядра от Microsoft на «живой» системе - без подключения второго компьютера. Если встроенная поддержка локальной отладки ядра действует только в Windows XP и Windows Server 2003, то LiveKd обеспечивает такую отладку в Windows NT 4.0, Windows 2000, Windows XP и Windows Server 2003.
LiveKd запускается точно так же, как Windbg или Kd. Эта утилита передает любые указанные параметры командной строки выбранному вами отладчику. По умолчанию LiveKd запускает отладчик Kd. Для запуска GUI-отлад-
чика (Windbg), задайте ключ
-w.Чтобы получить подсказку по ключам Live-Kd, укажите ключ -?.
LiveKd предоставляет отладчику смоделированный файл аварийного дампа (crash dump), поэтому вы можете выполнять в LiveKd любые операции, поддерживаемые для аварийных дампов. Поскольку LiveKd хранит смоделированный дамп в физической памяти, отладчик ядра может попасть в такую ситуацию, в которой структуры данных находятся в рассогласованном состоянии в процессе их изменения системой. При каждом запуске отладчик получает снимок состояния системы; если вы хотите обновить этот снимок, выйдите из отладчика (командой
q),и LiveKd спросит вас, нужно ли начать сначала. Если отладчик, выводя информацию на экран, вошел в цикл, нажмите клавиши Ctrl+C, чтобы прервать вывод, выйдите из отладчика и запустите его снова. Если он завис, нажмите клавиши Ctrl+Break, которые заставят завершить процесс отладчика. После этого вам будет предложено снова запустить отладчик.
SoftlCE
Еще один инструмент, не требующий двух машин для прямой отладки ядра, - SoftICE, который можно приобрести у Compuware NuMega
(
).SoftICE обладает во многом теми же возможностями, что и Windows Debugging Tools, но поддерживает переход между кодом пользовательского режима и режима ядра. Он также поддерживает DLL-модули расширения ядра Microsoft, поэтому большинство команд, описываемых нами в книге, будут работать и в SoftICE. Ha рис. 1-8 показан пользовательский интерфейс SoftICE, появляющийся при нажатии клавиши активизации SoftICE (по умолчанию - Ctrl+D); этот интерфейс представляет собой окно на рабочем столе системы, в которой он выполняется.
Platform Software Development Kit (SDK)
Platform SDK является частью подписки на MSDN уровня Professional и выше; кроме того, его можно бесплатно скачать с
.B нем содержатся документация, заголовочные файлы и библиотеки С, необходимые для компиляции и компоновки Windows-приложений. (Microsoft Visual C++ тоже поставляется с этими файлами, но их версии в Platform SDK всегда более новые и соответствуют самым последним версиям операционных систем Windows.) B Platform SDK для нас будут представлять интерес заголовочные файлы Windows API (\Program Files\Microsoft SDK\Include) и несколько утилит (Pfmon.exe, Pstat.exe, Pview.exe, Vadump.exe и Winobj.exe). Некоторые из них также поставляются с Ресурсами Windows и Support Tools. Наконец, отдельные утилиты поставляются с Platform SDK и MSDN Library как примеры исходного кода.
Device Driver Kit (DDK)
Windows DDK является частью подписки на MSDN уровня Professional и выше, но в отличие от Platform SDK его нельзя скачать бесплатно (впрочем, можно заказать CD-ROM за минимальную цену). Документация Windows DDK включается в MSDN Library.
Хотя DDK нацелен на разработчиков драйверов устройств, он представляет собой богатый источник информации о внутреннем устройстве Windows. Например, в главе 9 мы даем описание архитектуры подсистемы ввода-вывода, модели драйверов и структур данных базовых драйверов устройств, но не вдаемся в детали соответствующих функций ядра. A в документации Windows DDK исчерпывающе описаны все внутрисистемные функции и драйверы устройств.
Кроме документации в DDK входят заголовочные файлы, определяющие ключевые внутренние структуры данных, константы и интерфейсы многих внутрисистемных подпрограмм (в частности, обратите внимание на файлы Ntddk.h и Wdm.h). Эти файлы очень полезны в исследовании внутренних структур данных Windows с помощью отладчика ядра, так как мы даем лишь обобщенное описание внутренних структур, а в заголовочных файлах можно найти все подробности о каждом поле таких структур. B DDK также детально поясняются некоторые структуры данных (вроде заголовков для диспетчера объектов, блоки ожидания, события, мутанты, семафоры и др.).
Поэтому, если вы хотите поглубже покопаться в подсистеме ввода-вывода и в модели драйверов, читайте документацию DDK (особенно руководства Kernel-Mode Driver Architecture Design Guide и Reference). Еще один превосходный источник - книга Уолта Они (Walt Oney) «Programming the Microsoft Windows Driver Model, Second Edition» (Microsoft Press).
Утилиты Sysinternals
Bo многих экспериментах мы используем свободно распространяемые утилиты, которые можно скачать с
.Большинство этих ути-
лит написано Марком Руссиновичем, соавтором этой книги. K наиболее популярным утилитам относятся Process Explorer, Filemon и Regmon. Многие из этих утилит требуют установки и запуска драйверов устройств, работающих в режиме ядра, а значит, вам понадобятся полномочия администратора.
Резюме
B этой главе вы познакомились с ключевыми техническими концепциями и терминами Windows, которые будут использоваться во всей книге. Вы также получили первое представление о многих полезных инструментах, позволяющих изучать внутренние структуры данных Windows. Теперь вы готовы вместе с нами приступить к исследованию внутреннего устройства системы. Мы начнем с общего обзора архитектуры системы и ее основных компонентов.
Г Л A B A 2 Архитектура системы
Теперь, познакомившись с необходимыми терминами, понятиями и инструментами, мы можем рассмотреть задачи, которые ставились при разработке операционной системы Microsoft Windows. B этой главе описывается общая архитектура системы: ключевые компоненты, принципы их взаимодействия и контекст выполнения. Чтобы получить базовое представление о внутреннем устройстве Windows, давайте сначала обсудим требования и цели, обусловившие структуру и спецификацию этой системы.
Требования и цели проекта
Характеристики Windows NT в 1989 году определялись следующими требованиями. Операционная система должна:
(o)быть истинно 32-разрядной, реентерабельной, поддерживать вытесняющую многозадачность и работу с виртуальной памятью;
(o)работать на разных аппаратных платформах;
(o)хорошо масштабироваться в системах с симметричной мультипроцессорной обработкой;
(o)быть распределенной вычислительной платформой, способной выступать в роли как клиента сети, так и сервера;
(o)поддерживать большинство существующих 16-разрядных приложений
MS-DOS и Microsoft Windows 3.1;
(o)отвечать требованиям правительства к соответствию POSIX 1003.1;
(o)отвечать требованиям правительства и промышленности к безопасности операционных систем;
(o)обеспечивать простоту адаптации к глобальному рынку за счет поддержки Unicode.
Для создания системы, соответствующей предъявленным требованиям, нужно было принять тысячи решений. Поэтому перед командой разработчиков Windows NT на начальном этапе проекта были поставлены следующие цели.
(o) РасширяемостьКод должен быть написан так, чтобы системы можно было легко наращивать и модифицировать по мере изменения потребностей рынка.
(o)
ПереносимостьСистема должна работать на разных аппаратных архитектурах и обладать способностью к сравнительно легкому переносу на новые аппаратные архитектуры, если на рынке возникнет такая потребность.
(o)
Отказоустойчивость и надежностьСистема должна быть защищенной как от внутренних сбоев, так и от внешних деструктивных действий. У приложений не должно быть возможности нарушить работу операционной системы или других приложений.
(o)
СовместимостьХотя Windows NT должна расширить существующую технологию, ее пользовательский интерфейс и API должны быть совместимы с предыдущими версиями Windows и MS-DOS. Она также должна уметь взаимодействовать с другими системами вроде UNIX, OS/2 и NetWare.
(o)
ПроизводительностьC учетом ограничений, налагаемых поставленными целями, система должна быть максимально быстрой и отзывчивой независимо от аппаратной платформы.
По мере изучения деталей внутренней структуры Windows вы увидите, насколько успешно были реализованы все эти требования и цели. Ho сначала мы рассмотрим общую модель Windows и сравним ее с другими современными операционными системами.
Модель операционной системы
B большинстве многопользовательских операционных систем приложения отделены от собственно операционной системы: код ее ядра выполняется в привилегированном режиме процессора (называемом
режимом ядра),который обеспечивает доступ к системным данным и оборудованию. Код приложений выполняется в непривилегированном режиме процессора (называемом
пользовательским)с неполным набором интерфейсов, ограниченным доступом к системным данным и без прямого доступа к оборудованию. Когда программа пользовательского режима вызывает системный сервис, процессор перехватывает вызов и переключает вызывающий поток в режим ядра. По окончании работы системного сервиса операционная система переключает контекст потока обратно в пользовательский режим и продолжает его выполнение.
Windows, как и большинство UNIX-систем, является монолитной операционной системой - в том смысле, что большая часть ее кода и драйверов использует одно и то же пространство защищенной памяти режима ядра. Это значит, что любой компонент операционной системы или драйвер устройства потенциально способен повредить данные, используемые другими компонентами операционной системы.
Основана ли Windows на микроядре?
Хотя некоторые объявляют ее таковой, Windows не является операционной системой на основе микроядра в классическом понимании этого термина. B подобных системах основные компоненты операционной системы (диспетчеры памяти, процессов, ввода-вывода) выполняются как отдельные процессы в собственных адресных пространствах и представляют собой надстройки над примитивными сервисами микроядра. Пример современной системы с архитектурой на основе микроядра - операционная система Mach, разработанная в Carnegie MeI-lon University. Она реализует крошечное ядро, которое включает сервисы планирования потоков, передачи сообщений, виртуальной памяти и драйверов устройств. Все остальное, в том числе разнообразные API, файловые системы и поддержка сетей, работает в пользовательском режиме. Однако в коммерческих реализациях на основе микроядра Mach код файловой системы, поддержки сетей и управления памятью выполняется в режиме ядра. Причина проста: системы, построенные строго по принципу микроядра, непрактичны с коммерческой точки зрения из-за слишком низкой эффективности.
Означает ли тот факт, что большая часть Windows работает в режиме ядра, ее меньшую надежность в сравнении с операционными системами на основе микроядра? Вовсе нет. Рассмотрим следующий сценарий. Допустим, в коде файловой системы имеется ошибка, которая время от времени приводит к краху системы. Ошибка в коде режима ядра (например, в диспетчере памяти или файловой системы) скорее всего вызовет полный крах традиционной операционной системы. B истинной операционной системе на основе микроядра подобные компоненты выполняются в пользовательском режиме, поэтому теоретически ошибка приведет лишь к завершению процесса соответствующего компонента. Ho на практике такая ошибка все равно вызовет крах системы, так как восстановление после сбоя столь критически важного процесса невозможно.
Все эти компоненты операционной системы, конечно, полностью защищены от сбойных приложений, поскольку такие программы не имеют прямого доступа к коду и данным привилегированной части операционной системы (хотя и способны вызывать сервисы ядра). Эта защита - одна из причин, по которым Windows заслужила репутацию отказоустойчивой и стабильной операционной системы в качестве сервера приложений и платформы рабочих станций, обеспечивающей быстродействие основных системных сервисов вроде поддержки виртуальной памяти, файлового ввода-вывода, работы с сетями и доступа к общим файлам и принтерам.
Компоненты Windows режима ядра также построены на принципах объектно-ориентированного программирования (ООП). Так, для получения информации о каком-либо компоненте они, как правило, не обращаются к его структурам данных. Вместо этого для передачи параметров, доступа к структурам данных и их изменения используются формальные интерфейсы.
Однако, несмотря на широкое использование объектов, представляющих разделяемые системные ресурсы, Windows не является объектно-ориентированной системой в строгом понимании этого термина. Большая часть системного кода написана на C в целях переносимости и из-за широкой распространенности средств разработки на С. B этом языке нет прямой поддержки конструкций и механизмов ООП вроде динамического связывания типов данных, полиморфных функций или наследования классов.
Обзор архитектуры
Теперь обратимся к ключевым компонентам системы, составляющим ее архитектуру. Упрощенная версия этой архитектуры показана на рис. 2-1. Учтите, что упрощенная схема не отражает всех деталей архитектуры (например, здесь не показаны уровни сетевых компонентов и различных типов драйверов устройств).
Рис. 2-1.
Упрощенная схема архитектуры Windows
Ha рис. 2-1 прежде всего обратите внимание на линию, разделяющую те части Windows, которые выполняются в режиме ядра и в пользовательском режиме. Прямоугольники над этой линией соответствуют процессам пользовательского режима, а компоненты под ней - сервисам режима ядра. Как говорилось в главе 1, потоки пользовательского режима выполняются в защищенных адресных пространствах процессов (хотя при выполнении в режиме ядра они получают доступ к системному пространству). Таким образом, процессы поддержки системы, сервисов, приложений и подсистем окружения имеют свое адресное пространство.
Существует четыре типа пользовательских процессов:
(o)фиксированные
процессы поддержки системы(system support processes) - например, процесс обработки входа в систему и диспетчер сеансов, не являющиеся сервисами Windows (т. е. не запускаемые диспетчером управления сервисами);
(o)
процессы сервисов(service processes) - носители Windows-сервисов вроде Task Scheduler и Spooler. Многие серверные приложения Windows, например Microsoft SQL Server и Microsoft Exchange Server, тоже включают компоненты, выполняемые как сервисы;
(o)
пользовательские приложения(user applications) - бывают шести типов: для 32-разрядной Windows, 64-разрядной Windows, 16-разрядной Windows 3.1, 16-разрядной MS-DOS, 32-разрядной POSIX и 32-разрядной OS/2;
(o)
подсистемы окружения(environment subsystems) - реализованы как часть поддержки среды операционной системы, предоставляемой пользователям и программистам. Изначально Windows NT поставлялась с тремя подсистемами окружения: Windows, POSIX и OS/2. Последняя была изъята в Windows 2000. Что касается Windows XP, то в ней исходно поставляется только подсистема Windows - улучшенная подсистема POSIX доступна как часть бесплатного продукта Services for UNIX. Обратите внимание на прямоугольник «DLL подсистем», расположенный на рис. 2-1 под прямоугольниками «процессы сервисов» и «пользовательские приложения». B Windows пользовательские приложения не могут вызывать родные сервисы операционной системы напрямую, вместо этого они работают с одной или несколькими
DLL подсистем.Их назначение заключается в трансляции документированных функций в соответствующие внутренние (и обычно недокументированные) вызовы системных сервисов Windows. Трансляция может осуществляться как с помощью сообщения, посылаемого процессу подсистемы окружения, обслуживающему пользовательское приложение, так и без него.
Windows включает следующие компоненты режима ядра.
(o)
Исполнительная система(executive) Windows, содержащая базовые сервисы операционной системы, которые обеспечивают управление памятью, процессами и потоками, защиту, ввод-вывод и взаимодействие между процессами.
(o)
Ядро(kernel) Windows, содержащее низкоуровневые функции операционной системы, которые поддерживают, например, планирование потоков, диспетчеризацию прерываний и исключений, а также синхронизацию при использовании нескольких процессоров. Оно также предоставляет набор процедур и базовых объектов, применяемых исполнительной системой для реализации структур более высокого уровня.
(o)
Драйверы устройств(device drivers), в состав которых входят драйверы аппаратных устройств, транслирующие пользовательские вызовы функций ввода-вывода в запросы, специфичные для конкретного устройства, а также сетевые драйверы и драйверы файловых систем.
(o)
Уровень абстрагирования от оборудования(hardware abstraction layer, HAL), изолирующий ядро, драйверы и исполнительную систему Windows от специфики оборудования на данной аппаратной платформе (например, от различий между материнскими платами).
(o)
Подсистема поддержки окон и графики(windowing and graphics system), реализующая функции графического пользовательского интерфейса (GUI), более известные как Windows-функции модулей USER и GDL Эти функции обеспечивают поддержку окон, элементов управления пользовательского интерфейса и отрисовку графики.
B таблице 2-1 перечислены имена файлов основных компонентов Windows. (Вы должны знать их, потому что в дальнейшем мы будем ссылаться на некоторые системные файлы по именам.) Каждый из этих компонентов подробно рассматривается в этой и последующих главах.
Прежде чем детально рассматривать эти компоненты, давайте проясним, как достигается переносимость Windows между различными аппаратными платформами.
Переносимость
Windows рассчитана на разные аппаратные платформы, включая как CISC-системы Intel, так и RISC-системы. Windows NT первого выпуска поддерживала архитектуры
x86и MIPS. Спустя некоторое время была добавлена поддержка Alpha AXP производства DEC (DEC была приобретена Compaq, а позднее произошло слияние компаний Compaq и Hewlett Packard). (Хотя Alpha AXP был
64-разрядным процессором, Windows NT работала с ним в 32-разрядном режиме. B ходе разработки Windows 2000 была создана ее
64-разрядная версия специально под Alpha AXP, но в свет она так и не вышла.) B Windows NT 3.51 ввели поддержку четвертой процессорной архитектуры - Motorola PowerPC. B связи с изменениями на рынке необходимость в поддержке MIPS и PowerPC практически отпала еще до начала разработки Windows 2000. Позднее Compaq отозвала поддержку архитектуры Alpha AXP, и в Windows 2000 осталась поддержка лишь архитектуры
x86.B самые последние выпуски - Windows XP и Windows Server 2003 - добавлена поддержка трех семейств
64-разрядных процессоров: Intel Itanium IA
-64,AMD
x86-64и Intel
64-bit Extension Technology
(EM64T)для
x86(эта архитектура совместима с архитектурой AMD
x86-64,хотя есть небольшие различия в поддерживаемых командах). Последние два семейства процессоров называются
системами с 64-разрядными расширениямии в этой книге обозначаются как
x64.(Как
32-разрядные приложения выполняются в
64-разрядной Windows, объясняется в главе
3.)
Переносимость Windows между системами с различной аппаратной архитектурой и платформами достигается главным образом двумя способами.
(o)Windows имеет многоуровневую структуру. Специфичные для архитектуры процессора или платформы низкоуровневые части системы вынесены в отдельные модули. Благодаря этому высокоуровневая часть системы не зависит от специфики архитектур и аппаратных платформ. Ключевые компоненты, обеспечивающие переносимость операционной системы, - ядро (содержится в файле Ntoskrnl.exe) и уровень абстрагирования от оборудования (HAL) (содержится в файле Hal.dll). Функции, специфичные для конкретной архитектуры (переключение контекста потоков, диспетчеризация ловушек и др.), реализованы в ядре. Функции, которые могут отличаться на компьютерах с одинаковой архитектурой (например, в системах с разными материнскими платами), реализованы в HAL. Еще один компонент, содержащий большую долю кода, специфичного для конкретной архитектуры, - диспетчер памяти (memory manager), но если рассматривать систему в целом, такого кода все равно немного.
(o)Подавляющее большинство компонентов Windows написано на C и лишь часть из них - на C++. Язык ассемблера применяли только при создании частей системы, напрямую взаимодействующих с системным оборудованием (например, при написании обработчика ловушек прерываний) или требующих исключительного быстродействия (скажем, при переключении контекста). Ассемблерный код имеется не только в ядре и HAL, но и в составе некоторых других частей операционной системы: процедур, реализующих взаимоблокировку, механизма вызова локальных процедур (LPC), части подсистемы Windows, выполняемой в режиме ядра, и даже в некоторых библиотеках пользовательского режима (например, в коде запуска процессов в Ntdll.dll - системной библиотеке, о которой будет рассказано в этой главе несколько позже).
Конец бесплатного ознакомительного фрагмента.