Содержание
- Общие сведения о процессах и потоках в ОС Windows. Понятие объекта ядра. Типы объектов ядра
- Объекты ядра в windows
- Объекты. Менеджер объектов. Реестр
- Введение
- Объекты ядра
- Структура объекта. Методы объекта
- Методы объекта
- Описатели объектов
- Именование объектов. Разделяемые ресурсы
- Ядро Windows
- Объекты ядра.
- Эксперимент: просмотр KPCR и KPRCB.
- Новые книги
- Что такое объект ядра
- Учет пользователей объектов ядра
- Защита
- Таблица описателей объектов ядра
- Создание объекта ядра
- Закрытие объекта ядра
- Совместное использование объектов ядра несколькими процессами
- Наследование описателя объекта
Общие сведения о процессах и потоках в ОС Windows. Понятие объекта ядра. Типы объектов ядра
Управление процессами и потоками в мультипрограммных ОС.
Общие сведения о процессах и потоках в ОС Windows. Понятие объекта ядра. Типы объектов ядра.
Любой процесс в ОС Windows определяется как основа выполняемой программы, состоящая из двух компонентов:
1. Объект ядра – это та её часть, которая включает служебные структуры данных, с помощью которых, при вызове системных функций, осуществляется управление выполнением программ потоков процесса;
Средствами системы могут создаваться несколько типов объектов ядра, с помощью которых могут выполняться различные операции. Примерами таких объектов являются:
1. Процессы – Process objects;
3. Проекции файлов – Files mapping;
6. Семафоры – Semaphore;
7. Почтовые ящики – Mails;
5, 6 – объекты синхронизации. 7, 8 – объект обмена данными.
Каждый объект интерпретируется в системе, как некоторая служебная структура памяти, в элементах которой указывается информация об объекте. Часть элементов этой структуры присутствует во всех типах объектов. Некоторые являются специфичными для каждого отдельного типа. Все объекты создаются системными функциями. Программа пользователя может обращаться к объектам ядра с помощью этих функций. Когда функция вызывается, то в результате своего выполнения, она создает соответствующий объект ядра, заполняет её исходными данными, и возвращает в программу дескриптор объекта, который далее и используется в программе пользователя.
В ОС, кроме объектов ядра, существуют и могут использоваться объекты других типов, например: окна, меню, шрифты, курсоры мыши, и рад других. Перечисленные объекты относятся к GDI – объектам пользовательского интерфейса.
Для того чтобы процесс мог бы быть запущен на выполнение, в системе должен быть создан соответствующий объект ядра, и кроме того, образован хотя бы один поток процесса. В потоке должна выполняться последовательность команд требуемой прикладной или системной программы. Для этого, процессу при его запуске выделяется область адресного пространства памяти (виртуального адресного пространства, которое при выполнении в процессоре трансформируется в физическое адресное пространство).
Любой процесс может иметь несколько потоков. Каждому потоку при его создании предоставляется возможность использования индивидуального набора регистров процессора, и собственного стека. Совокупность состояний регистров и области памяти, отводимой под стек, образует контекст потока.
Чтобы все потоки процесса выполнялись в мультипрограммном режиме, система периодически отводит каждому из них квант процессорного времени, в соответствии с дисциплиной распределения RR.
В некоторых версиях Windows все потоки процесса выполняются на одном и том же процессоре, то есть в системе реализуется режим мультипрограммной работы на одном процессоре с вытесняющей многозадачностью.
Начиная с некоторых версий Windows 2000 возможен режим, при котором программными средствами каждый поток закрепляется за отдельным процессором, если процессорная часть компьютера позволяет это сделать. В этом случае, обеспечивается мультипроцессорный мультипрограммный режим. Аналогичный режим реализуется в компьютерах с многоядерными процессорами.
Все пользовательские программы, выполняемые под управлением Windows, подготавливаются программистами с помощью соответствующих систем программирования. В большинстве из них, основная часть исходного кода программы размещается программистом внутри т.н. основной или входной функции. Существует несколько видов таких функций:
w – использование Юникода.
Существуют особенности в выполнении этих функций. В момент запуска на выполнение программного кода этих функций, управление получают не первые команды тела этих функций, а происходит обращение (вызов) другой функции системы программирования, которая называется стартовой функцией. Она хранится в библиотеке системы программирования и автоматически включается в исполняемый файл программы потока компоновщиком на этапе создания этого файла.
Стартовая функция реализует следующие операции общесистемного характера:
1. Считывает из памяти указатель на полную командную строку запускаемого процесса;
2. Инициализирует глобальные переменные из библиотеки системы программирования;
3. Считывает указатель на переменные системного окружения процесса;
4. Инициализирует динамически используемую область памяти, отводимую для программы потока;
5. Вызывает конструкторы всех глобальных и статических объектов для соответствующих классов объектно-ориентированной системы программирования;
6. Передает управление на первую исполняемую команду основной функции программы первичного потока.
После этого, программа начинает выполняться в обычном режиме. После того, как выполнятся до конца все команды основной функции, управление снова возвращается к стартовой функции. Она вызывает деструкторы всех глобальных и статических объектов в программе первичного потока.
Если к этому моменту все другие потоки процесса завершились, стартовая функция вызывает функцию завершения процесса ExitProcess (). Эта функция уничтожает процесс (его объект ядра) и устанавливает код его завершения.
Источник
Объекты ядра в windows
Объекты ядра используются системой и нашими приложениями для управления множеством разных ресурсов: процессами, потоками, файлами и т.д.
Система позволяет создавать и оперировать несколькими типами таких объектов, в том числе: маркерами доступа (access token objects), файлами (file objects), проекциями файлов (file-mapping objects), портами завершения ввода вывода (I/O completion port objects), заданиями (jobs), почтовыми ящиками (mailslot objects), мьютексами (mutex objects), каналами (pipe objects), процессами (thread objects) и ожидаемыми таймерами (waitable timer objects).
Эти объекты создаются Windows-функциями. Например, CreateFileMapping заставляет систему сформировать объект проекцию файла. Каждый объект ядра на самом деле просто блок памяти, выделенный ядром и доступный только ему.
Приложение не может напрямую обращаться к объектам ядра читать и изменять их содержимое.
Для взаимодействия с объектами ядра у Windows предусмотрен набор функций, обрабатывающих структуры объектов ядра по строго определенным правилам. Когда мы создаем объект ядра, функция возвращает описатель идентифицирующий созданный объект (HANDLE). Все операции с текущим объектом ядра возможны только при указании этого описателя управляющей функции.
Для большей защиты, описатели уникальны только внутри конкретного процесса. Поэтому, передавая по межпроцессорной связи описатель объекта другому процессу, используя описатель в другом процессе, мы получим ошибку. Это ограничение можно обойти, но об этом позже.
Учет пользователей объектов ядра.
Объекты ядра принадлежат ядру, а не процессу. Это говорит о том, что завершая работу с процессом, мы не обязательно разрушаем объект ядра. В большинстве случаев объект разрушается, но если созданный вами объект ядра используется другим процессом, ядро запретит разрушение объекта до тех пор, пока от него не откажется последний пользователь.
В каждом объекте, как уже говорилось, есть счетчик пользователей объектом. В момент создания счетчику присваивается значение 1. Соответственно, при обращении к нему другого процесса, счетчик увеличивается на 1. Когда пользовательский процесс завершается, счетчик уменьшается. Система удаляет объект ядра, когда счетчик обнуляется.
Почти во всех функциях, создающих объекты, есть параметр SECURITY_ATTRIBUTES. Он необходим для защиты объектов ядра от несанкционированного доступа. Чаще всего это свойство используют в серверных приложениях, в клиентских приложениях этот объект можно игнорировать.
Если вы пишете для win98, то там такое свойство отсутствует, но для корректной работы таких приложений в Win2000 и выше, стоит помнить о работе с соответствующими механизмами.
При передаче в таком атрибуте NULL большинство объектов будут созданы со стандартными свойствами защиты, когда к объекту допускаются: создатель и администраторская группа. Остальные игнорируются.
Более подробно о защите объектов ядра в следующий раз.
Источник
Объекты. Менеджер объектов. Реестр
Введение
создающего семафор, возвращаемый описатель hSemaphore необходим приложению для последующей работы с этим семафором.
Объекты ядра
В рамках данного курса нам придется активно использовать объекты, называемые в руководствах по Win32-программированию объектами ядра ( kernel objects). Поддержка объектов ядра осуществляется собственно ядром и исполнительной системой. Помимо объектов ядра имеются также объекты, предназначенные для управления окнами ( User ), и объекты, предназначенные для управления графикой ( GDI ). Изучение этих категорий объектов, реализуемых подсистемой поддержки окон и графики и ориентированных на разработку графических интерфейсов пользователя, выходит за пределы данного курса.
Внешнее отличие объектов ядра (объектов исполнительной системы) от объектов User и GDI состоит в наличии у первых атрибутов защиты, которые являются одним из параметров, создающих объект ядра функций. Далее эти объекты ядра (объекты исполнительной системы) будут называться просто объектами.
Объект представляет собой блок памяти в виртуальном адресном пространстве ядра. Этот блок содержит информацию об объекте в виде структуры данных (см. ниже «структура объекта»). Структура содержит как общие, так и специфичные для каждого объекта элементы. Объекты создаются в процессе загрузки и функционирования ОС и теряются при перезагрузке и выключении питания.
Содержимое объектов доступно только ядру, приложение не может модифицировать его непосредственно. Доступ к объектам можно осуществить только через его функции-методы ( инкапсуляция данных ), которые инициируются вызовами некоторых библиотечных Win32-функций.
Структура объекта. Методы объекта
Методы объекта
Описатели объектов
Создание новых объектов, или открытие по имени уже существующих, приложение может осуществить при помощи Win32-функций, таких, как CreateFile, CreateSemaphore, OpenSemaphore и т.д. Это библиотечные процедуры, за которыми стоят сервисы Windows и методы объектов. В случае успешного выполнения создается 64-битный описатель в таблице описателей процесса в памяти ядра. На эту таблицу есть ссылка из блока управления процессом EPROCESS (см. «Реализация процессов и потоков» ).
Именование объектов. Разделяемые ресурсы
Источник
Ядро Windows
Ядро состоит из набора функций, находящихся в файле Ntoskrnl.exe. Этот набор предоставляет основные механизмы (службы диспетчеризации потоков и синхронизации), используемые компонентами исполняющей системы, а также поддержкой архитектурно-зависимого оборудования низкого уровня (например, диспетчеризацией прерываний и исключений), которое имеет отличия в архитектуре каждого процессора.
Код ядра написан главным образом на C, с ассемблерным кодом, предназначенным для задач, требующих доступа к специальным инструкциям и регистрам процессора, доступ к которым из кода на языке C затруднен.
Подобно различным вспомогательным функциям, ряд функций ядра документированы в WDK (и их описание может быть найдено при поиске функций, начинающихся с префикса Ke), поскольку они нужны для реализации драйверов устройств.
Объекты ядра.
Ядро предоставляет низкоуровневую базу из четко определенных, предсказуемых примитивов и механизмов операционной системы, позволяющую высокоуровневым компонентам исполняющей системы выполнять свои функции. Само ядро отделено от остальной исполняющей системы путем реализации механизмов операционной системы и уклонения от выработки политики. Оно оставляет почти все политические решения, за исключением планирования и диспетчеризации потоков, реализуемых ядром, за исполняющей системой.
За пределами ядра исполняющая система представляет потоки и другие ресурсы совместного использования в виде объектов. Эти объекты требуют некоторых издержек, например, на дескрипторы для управления ими, на проверки безопасности для их защиты и на ресурсные квоты, выделяемые при их создании.
В ядре, реализующем набор менее сложных объектов, называемых «объектами ядра», подобные издержки исключены, что помогает ядру управлять основной обработкой и поддерживать создание исполняющих объектов. Большинство объектов уровня исполнения инкапсулируют один или несколько объектов ядра, принимая их, определенные в ядре свойства.
Один набор объектов ядра, называемых «управляющими объектами», определяет семантику управления различными функциями операционной системы.
В этот набор включены объекты асинхронного вызова процедур — APC, отложенного вызова процедур — deferred procedure call (DPC), и несколько объектов, используемых диспетчером ввода-вывода, например, объект прерывания.
Еще один набор объектов ядра, известных как «объекты-диспетчеры», включает возможности синхронизации, изменяющие или влияющие на планирование потоков. Объекты-диспетчеры включают поток ядра, мьютекс (называемый среди специалистов «мутантом»), событие, пару событий ядра, семафор, таймер и таймер ожидания. Исполняющая система использует функции ядра для создания экземпляров объектов ядра, работы с ними и создания более сложных объектов, предоставляемых в пользовательском режиме.
Область ядра, относящаяся к управлению процессором, и блок управления (KPCR и KPRCB).
Для хранения специфических для процессора данных ядром используется структура данных, называемая областью, относящейся к управлению процессором, или KPCR (KernelProcessorControlRegion). KPCR содержит основную информацию, такую как процессорная таблица диспетчеризации прерываний (interrupt dispatch table, IDT), сегмент состояния задачи (task-state segment, TSS) и таблица глобальных дескрипторов (globaldescriptortable, GDT). Она также включает состояние контроллера прерываний, которое используется вместе с другими модулями, такими как ACPI-драйвер и HAL.
Для обеспечения простого доступа к KPCR ядро хранит указатель на эту область в регистре fs на 32-разрядной системе Windows и в регистре gs на Windows-системе x64. На системах IA64 KPCR всегда находится по адресу 0xe0000000ffff0000.
KPCR также содержит вложенную структуру данных, которая называется блоком управления процессором (kernelprocessorcontrolblock, KPRCB). В отличие от области KPCR, которая документирована для драйверов сторонних производителей и для других внутренних компонентов ядра Windows, KPRCB является закрытой структурой, используемой только кодом ядра, который находится в файле Ntoskrnl.exe.
В этом блоке содержится:
В KPRCB также содержится вся статистика процессора, такая как статистика ввода-вывода, статистика диспетчера кэша, статистика DPC и статистика диспетчера памяти. И наконец, KPRCB иногда используется для хранения структур выравнивания границ кэша для каждого процессора, необходимых для оптимизации доступа к памяти, особенно на NUMA-системах. Например, система невыгружаемого и выгружаемого пула со стороны выглядит как списки, хранящиеся в KPRCB.
Эксперимент: просмотр KPCR и KPRCB.
Если в системе имелись задержанные DPC-вызовы, эта информация также будет отображена на экране.
Источник
Новые книги
ГЛАВА 3 Объекты ядра
Изучение Windows API мы начнем с объектов ядра и их описателей (handles). Эта глава посвящена сравнительно абстрактным концепциям, т. e. мы, не углубляясь в специфику тех или иных объектов ядра, рассмотрим их общие свойства.
Я бы предпочел начать с чего-то более конкретного, но без четкого понимания объектов ядра Вам не стать настоящим профессионалом в области разработки Windows-программ. Эти объекты используются системой и нашими приложениями для управления множеством самых разных ресурсов процессами, потоками, файлами и т. д. Концепции, представленные здесь, будут встречаться на протяжении всей книги. Однако я прекрасно понимаю, что часть материалов не уляжется у Вас в голове до тех пор, пока Вы не приступите к работе с объектами ядра, используя реальные функции. И при чтении последующих глав книги Вы, наверное, будете время от времени возвращаться к этой главе.
Что такое объект ядра
Создание, открытие и прочие операции с объектами ядра станут для Вас, как разработчика Windows-приложений, повседневной рутиной. Система позволяет создавать и оперировать с несколькими типами таких объектов, в том числе, маркерами доступа (access token objects), файлами (file objects), проекциями файлов (file-mapping objects), портами завершения ввода-вывода (I/O completion port objects), заданиями (job objects), почтовыми ящиками (mailslot objects), мьютсксами (mutex objects), каналами (pipe objects), процессами (process objects), семафорами (semaphore objects), потоками (thread objects) и ожидаемыми таймерами (waitable timer objects). Эти объекты создаются Windows-функциями Например, CreateFtleMapping заставляет систему
сформировать объект «проекция файла». Каждый объект ядра — на самом деле просто блок памяти, выделенный ядром и доступный только ему. Этот блок представляет собой структуру данных, в элементах которой содержится информация об объекте. Некоторые элементы (дескриптор защиты, счетчик числа пользователей и др.) присутствуют во всех объектах, но большая их часть специфична для объектов конкретного типа. Например, у объекта «процесс» есть идентификатор, базовый приоритет и
код завершения, а у объекта «файл» — смещение в байтах, режим разделения и режим открытия
Поскольку структуры объектов ядра доступны только ядру, приложение не может самостоятельно найти эти структуры в памяти и напрямую модифицировать их содержимое Такое ограничение Microsoft ввела намеренно, чтобы ни одна программа не нарушила целостность структур объектов ядра. Это же ограничение позволяет Microsoft вводить, убирать или изменять элементы структур, нс нарушая работы каких-либо приложений.
Но вот вопрос: если мы не можем напрямую модифицировать эти структуры, то как же наши приложения оперируют с объектами ядра? Ответ в том, что в Windows
предусмотрен набор функций, обрабатывающих структуры объектов ядра по строго определенным правилам. Мы получаем доступ к объектам ядра только через эти функции. Когда Вы вызываете функцию, создающую объект ядра, она возвращает описатель, идентифицирующий созданный объект, Описатель следует рассматривать как «непрозрачное» значение, которое может быть использовано любым потоком Вашего процесса. Этот описатель Вы передаете Windows-функциям, сообщая системе, какой
объект ядра Вас интересует. Но об описателях мы поговорим позже (в этой главе).
Для большей надежности операционной системы Microsoft сделала так, чтобы значения описателей зависели от конкретного процесса. Поэтому, если Вы передадите такое значение (с помощью какого-либо механизма межпроцессной связи) потоку другого процесса, любой вызов из того процесса со значением описателя, полученного в Вашем процессе, даст ошибку. Но не вользуйтесь, в конце главы мы рассмотрим три механизма корректного использования несколькими процессами одного объекта ядра.
Учет пользователей объектов ядра
Объекты ядра принадлежат ядру, а не процессу. Иначе говоря, если Ваш процесс вызывает функцию, создающую объект ядра, а затем завершается, объект ядра может быть не разрушен. В большинстве случаев такой объект все же разрушается; но если созданный Вами объект ядра используется другим процессом, ядро запретит разрушение объекта до тех пор, пока от него не откажется и тот процесс.
Ядру известно, сколько процессов использует конкретный объект ядра, посколь ку в каждом объекте есть счетчик числа его пользователей. Этот счетчик — один из элементов данных, общих для всех типов объектов ядра. В момепт создания объекта счетчику присваивается 1. Когда к существующему объекту ядра обращается другой процесс, счетчик увеличивается на 1. А когда какой-то процесс завершается, счетчики всех используемых им объектов ядра автоматически уменьшаются на 1. Как только счетчик какого-либо объекта обнуляется, ядро уничтожает этот объект.
Защита
Объекты ядра можно защитить дескриптором защиты (security descriptor), который описывает, кто создал объект и кто имеет права на доступ к нему. Дескрипторы защиты обычно используют при написании серверных приложений; создавая клиентское приложение, Вы можете игнорировать это свойство объектов ядра.
WIN98:
В Windows 98 дескрипторы защиты отсутствуют, так как она не предназначена для выполнения серверных приложений. Тем не менее Вы должны знать о тонкостях, связанных с защитой, и реализовать соответствующие механизмы, чтобы Ваше приложение корректно работало и в Windows 2000.
Почти все функции, создающие объекты ядра, принимают указатель на структуру SECURITY_ATTRIBUTES как аргумент, например:
HANDLE CreateFileMapping(
HANDLE hFile.
PSECURITY_ATTRIBUTES psa,
DWORD flProtect,
DWORD dwMaximumSizeHigh,
DWORD dwMaximuniSizeLow,
PCTSTR pszNarne);
Большинство приложений вместо этого аргумента передает NULL и гоздает объект с защитой по умолчанию. Такая защита подразумевает, что создатель объекта и любой член группы администраторов получают к нему полный доступ, а все прочие к объекту не допускаются Однако Вы можете создать и инициализировать структуру SECURITY_ATTRIBUTES, а затем передать ее адрес. Она выглядит так:
typedef struct _SECURITY_ATTRIBUTES <
DWORD nLength,
LPVOID lpSecurityDescriptor;
BOOL bInherttHandle;
> SECURITY_ATTRIBUTES;
Хотя структура называется SECURITY__ATTRIBUTES, лишь один cc элемент имеет отношение к защите — lpSecuntyDescnptor. Если надо ограничить доступ к созданному Вами объекту ядра, создайте дескриптор защиты и инициализируйте структуру SECURITY_ATTRIBUTES следующим образом:
sa.nLength = sizeof(sa); // используется для выяснения версий
sa.lpSecuntyDescriptor = pSD, // адрес инициализированной SD
sa.bInheritHandle = FALSE; // об этом позже
HANDLE hFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_REAOWRITE, 0, 1024, «MyFileMapping»);
Рассмотрение элемента bInheritHandle я отложу до раздела о наследовании, так как этот элемент не имеет ничего общего с защитой.
Желая получить доступ к существующему объекту ядра (вместо того чтобы создавать новый), укажите, какие операции Вы намерены проводить над обьектом. Например, если бы я захотел считывать данные из существующей проекции файла, то вызвал бы функцию OpenFileMapping таким образом;
HANDLE hFileMapping = OpenFileMapping(FILE_MAP_READ, FALSE, «MyFileMapping»);
Передавая FILE_MAPREAD первым параметром в функцию OpenFileMapping, я сообщаю, что, как только мне предоставят доступ к проекции файла, я буду считывать из нее данные. Функция OpenFileMapping, прежде чсм вернуть действительный описатель, проверяет тип защиты объекта. Если меня, как зарегистрировавшегося пользователя, допускают к существующему объекту ядра «проекция файла», OpenFileMapping возвращает действительный описатель. Но если мне отказывают в доступе, OpenFileMapping
возвращает NULL, а вызов GetLastError дает код ошибки 5 (или ERROR_ACCESS_DENIED). Но опять же, в основной массе приложений защиту не используют, и поэтому я больше не буду задерживаться на этой теме
WINDOWS 98:
Хотя в большинстве приложений нет нужды беспокоиться о защите, многие функции Windows требуют, чтобы Вы передавали им информацию о нужном уровне защиты. Некоторые приложения, написанные для Windows 98, в Windows 2000 толком не работают из-за того, что при их реализации не было уделено должного внимания защите.
Представьте, что при запуске приложение считывает данные из какого-то раздела реестра Чтобы делать это коррекчно, оно должно вызывать функцию RegOpenKeyEx, передавая значение KEY_QUERY_VALUE, которое разрешает операцию чтения в указанном разделе.
Однако многие приложения для Windows 98 создавались без учета специфики Windows 2000 Поскольку Windows 98 не защищает свой реестр, разработчики часто вызывали RegQpenKeyEx со значением KEY_ALL_ACCESS. Так проще и не надо ломать голову над том, какой уровень доступа требуется на самом деле. Но проблема в том, что раздел реестра может быть доступен для чтения и блокирован для записи. В Windows 2000 вызов RegOpenKeyEx со значением KEY_ALL_ACCESS заканчивается неудачно, и без соответствующего контроля ошибок приложение может повести себя совершенно непредсказуемо.
Если бы разработчик хоть немного подумал о защите и поменял значение KEY_ALL_ACCESS на KEY_QUERY_VALUE (только-то и всего!), его продукт мог бы работать в обеих операционных системах
Пренебрежение флагами, определяющими уровень доступа, — одна из самых крупных ошибок, совершаемых разработчиками Правильное их использование позволило бы легко перенести многие приложения Windows 98 в Windows 2000
Кроме объектов ядра Ваша программа может использовать объекты других типов — меню, окна, курсоры мыши, кисти и шрифты. Они относятся к объектам User или GDI Новичок в программировании для Windows может запутаться, пытаясь отличить объекты User или GDI от объектов ядра. Как узнать, например, чьим объектом — User или ядра — является данный значок? Выяснить, не принадлежит ли объект ядру, проще всего так проанализировать функцию, создающую объект. Практически у всех функций, создающих объекты ядра, есть параметр, позволяющий указать атрибуты защиты, — как у CreateFileMapping.
В то же время у функций, создающих объекты User или GDI, нет параметра типа PSECURITY_ATTRIBUTES, и пример тому — функция CreateIcon
HICON CreateIcon(
HINSTANCE hinst.
int nWidth,
int nHeight,
BYTE cPlanes,
BYTE cBitsPixel,
CONST BYTE *pbANDbits,
CONST BYTE *pbXORbits);
Таблица описателей объектов ядра
При инициализации процесса система создает в нем таблицу описатслсй, используемую только для объектов ядра. Сведения о структуре этой таблицы и управлении ею незадокументированы Вообще-то я воздерживаюсь от рассмотрения недокументиро ванных частей операционных систем. Но в данном случае стоит сделать исключение, — квалифицированный Windows-программист, на мой взгляд, должен понимать, как устроена таблица описателей в процессе. Поскольку информация о таблице описателей незадокументирована, я не ручаюсь за ее стопроцентную достоверность и к тому же эта таблица по-разному реализуется в Windows 2000, Windows 98 и Windows СЕ. Таким образом, следующие разделы помогут понять, что представляет собой таблица описателей, но вот что система действительно делает с ней — этот вопрос я оставляю открытым.
В таблице 3-1 показано, как выглядит таблица описателей, принадлежащая про цессу Как видите, это просто массив структур данных Каждая структура содержит указатель на какой-нибудь объект ядра, маску доступа и некоторые флаги
Индекс | Указатель на блок памяти объекта ядра | Маска доступа (DWORD с набором битовых флагов) | Флаги (DWORD с набором битовых флагов) |
1 | 0х. | 0х. | 0x. |
2 | 0х. | 0x. | 0x. |
Таблица 3-1. Структура таблицы описателей, принадлежащей процессу
Создание объекта ядра
Когда процесс инициализируется в первый paз, таблица описателей еще пуста. Но стоит одному из его потоков вызвать функцию, создающую объект ядра (например, CreateFtleMapping), как ядро выделяет для этого объекта блок памяти и инициализирует его, далее ядро просматривает таблицу описателей, принадлежащую данному процессу, и отыскивает свободную запись. Поскольку таблица еще пуста, ядро обнаруживает структуру с индексом 1 и инициализирует ее. Указатель устанавливается на внутренний адрес структуры данных объекта, маска доступа — на доступ без ограничений и, наконец, определяется последний компонент — флаги (О флагах мы поговорим позжс, в разделе о наследовании )
Вот некоторые функции, создающие объекты ядра (список ни в коей мере на полноту не претендует)
HANDLE CreateThread(
PSECURITY_ATTRIBUTES psa,
DWORD dwStackSize,
PTHREAD_START_ROUTINE pfnStartAddr,
PVOID pvParam,
DWORD dwCreationFlags,
PDWORD pdwfhreadId);
HANDEE CreateFile(
PCTSTR pszFileName,
DWORD dwDesiredAccebS,
DWORD dwShareMode,
PSECURITY_ATTRIBUTES psa,
DWORD dwCreationDistribution,
DWORD dwFlagsAndAttnbutes,
HANDEE hTemplateFile);
HANDLE CreateFileMapping(
HANDLE hFile,
PSECURITY_ATTRIBUTES psa,
DWORD flProtect,
DWORD dwMdximumSizcHigh,
DWORD dwMaximumSizeLow,
PCTSTR pszName);
HANDLE CreateSemaphore(
PSECURITY_ATTRIBUTES psa,
LONG lInitialCount,
LONG lMaximumCount,
PCTSTR pszName);
Все функции, создающие объекты ядра, возвращают описатели, которые привязаны к конкретному процессу и могут быть использованы в любом потоке данного процесса Значение описателя представляет собой индекс в таблице описателей, принадлежащей процессу, и таким образом идентифицирует место, где хранится информация, связанная с объектом ядра. Вот поэтому при отладке своего приложения и просмотре фактического значения описателя объекта ядра Вы и видите такие малые величины: 1, 2 и т. д. Но помните, что физическое содержимое описателей не задокументировано и может быть изменено. Кстати, в Windows 2000 это значение определяет, по сути, не индекс, а скорее байтовое смещение нужной записи от начала таблицы описателей.
Всякий раз, когда Вы вызываете функцию, принимающую описатель объекта ядра как аргумент, Вы передаете ей значение, возвращенное одной из Create-функций. При этом функция смотрит в таблицу описателей, принадлежащую Вашему процессу, и считывает адрес нужного объекта ядра.
Если Вы передаете неверный индекс (описатель), функция завершается с ошибкой и GetLastError возвращает 6 (ERROR_INVALID_HANDLE). Это связано с тем, что на самом деле описатели представляют собой индексы в таблице, их значения привязаны к конкретному процессу и недейовительны в других процессах.
HANDLE hMutex = CreateMutex(. );
if (hMutex == lNVALID_HANDLE_VALUE) <
// этот код никогда не будет выполнен, так как
// при ошибке CreateMutex возвращает NLlLL
>
Точно так же бессмыслен и следующий код:
HANDIE hFile = CreateFile(.. );
if (hFile — NULL> <
// и этот код никогда не будет выполнен, так как
// при ошибке CreateFile возвращает lNVALID_HANDLE_VALUE (-1)
>
Закрытие объекта ядра
Независимо от того, как именно Вы создали объект ядра, по окончании работы с ним его нужно закрьпь вызовом CloseHandle
BOOL CloseHandle(HANDLE hobj);
Эта функция сначала проверяет таблицу описателей, принадлежащую вызывающему процессу, чтобы убедиться, идентифицирует ли переданный ей индекс (описа
тель) объект, к которому этот процесс действительно имеет доступ. Если переданный индекс правилен, система получает адрес структуры данных объекта и уменьшает в этой структуре счетчик числа пользователей; как только счетчик обнулится, ядро удалит объект из памяти.
Если же описатель невереи, происходит одно из двух. В нормальном режиме выполнения процесса CloseHandle возвращает FALSE, a GetLastError — код ERROR_INVALID_HANDLE. Но при выполнении процесса в режиме отладки система просто уведомляет отладчик об ошибке.
Перед самым возвратом управления CloseHandle удаляет соответствующую запись из таблицы описателей: данный описатель тспсрь недействителен в Вашем процессе и использовать его нельзя. При этом запись удаляется независимо от того, разрушен объект ядра или нет! После вызова CloseHandle Вы больше не получите доступ к это-
му объекту ядра; но, если его счетчик не обнулен, объект остается в памяти Тут все нормально, это означает лишь то, что объект используется другим процессом (или процессами). Когда и остальные процессы завершат свою работу с этим объектом (тоже вызвав CloseHandle), он будет разрушен.
А вдруг Вы забыли вызвать CloseHandle — будет ли утечка памяти? И да, и нет. Утечка ресурсов (тех же объектов ядра) вполне вероятна, пока процесс еще исполняется. Однако по завершении процесса операционная система гарантированно освобождает все ресурсы, принадлежавшие этому процессу, и в случае объектов ядра действует так: в момент завершения процесса просматривает его таблицу описателей и закрывает любые открытые описатели.
Совместное использование объектов ядра несколькими процессами
Время от времени возникает необходимость в разделении объектов ядра между потоками, исполняемыми в разных процессах. Причин тому может быть несколько:
• объекты «проекции файлов» позволяют двум процессам, исполняемым на одной машине, совместно использовать одни и те же блоки данных;
• почтовые ящики и именованные каналы дают возможность программам обмениваться данными с процессами, исполняемыми на других машинах в сети;
• мьютексы, семафоры и события позволяют синхронизировать потоки, исполняемые в разных процессах, чтобы одно приложение могло уведомитьдругое об окончании той или иной операции.
Но поскольку описатели объектов ядра имеют смысл только в конкретном процессе, разделение объектов ядра между несколькими процессами — задача весьма непростая. У Microsoft было несколько веских причин сделать описатели процессно-зависимыми», и самая главная — устойчивость операционной системы к сбоям. Если бы описатели объектов ядра были общесистемными, то один процесс мог бы запросто получить описатель объекта, используемого другим процессом, и устроить в нем (этом процессе) настоящий хаос. Другая причина — защита. Объекты ядра защищены, и процесс, прежде чсм оперировать с ними, должен запрашивать разрешение на доступ к ним.
Три механизма, позволяющие процессам совместно использовать одни и те же объекты ядра, мы рассмотрим в следующем разделе.
Наследование описателя объекта
Наследование применимо, только когда процессы связаны родственными отношениями (родительский-дочерний). Например, родительскому процессу доступен один или несколько описателей объектов ядра, и он решает, породив дочерний процесс, передать ему по наследству доступ к своим объектам ядра. Чтобы такой сценарий наследования сработал, родительский процесс должен выполнить несколько операций.
Во-первых, еще при создании объекта ядра этот процесс должен сообщить системе, что ему нужен наследуемый описатель данного объекта. (Имейте в виду описатели объектов ядра наследуются, но сами объекты ядра — нет.)
Чтобы создать наследуемый описатель, родительский процесс выделяет и инициализирует структуру SECURITY_ATTRIBUTES, а затем передает ее адрес требуемой Create-функции. Следующий код создаст объект-мьютекс и возвращает его описатель:
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecuntyDescriptor = NULL;
sa.bInheritHandle =- TRUE; // делаем возвращаемый описатель наследуемым
HANDLE hMutex = CreateMutex(&sa, FALSE, NULL);
Этот код инициализирует структуру SECURTY_ATTRIBUTES, указывая, что объект следует создать с защитой по умолчанию (в Windows 98 это игнорируется) и что возвращаемый описательдолжен быть наследуемым.
WINDOWS 98:
Хотя Windows 98 не полностью поддерживает защиту, она все же поддержива-
ет наследование и поэтому корректно обрабатывает элемент bInheritHandle.
А теперь перейдем к флагам, которые хранятся в таблице описателей, принадлежащей процессу В каждой ее записи присутствует битовый флаг, сообщающий, является данный описатель наследуемым или нет. Если Вы, создавая объект ядра, передадите в парамере типа PSECURITY_ATTRIBUTES значение NULL, то получите ненаследуемый описатель, и этот флаг будет нулевым. А если элемент bInheritHandle равен TRUE, флaгy пpиcвaивaeтcя 1.
Допустим, какому-то процессу принадлежит таблица описателей, как в таблице 3-2.
Указатель на блок памяти объекта ядра
Маска доступа (DWORD с набором битовых флагов)
Источник
Аннотация: В лекции описаны особенности функционирования менеджера объектов — одного из ключевых компонентов ОС Windows. Объекты активно используются для организации доступа к ресурсам, которые нужно защищать, именовать, разделять и т. д. Среди совокупности объектов выделены объекты ядра. Описаны дескрипторы объектов, отвечающие за связь объекта с приложением. Рассмотрены вопросы именования объектов и связь пространства имен объектов с другими пространствами имен. Для управления большим организована специальная централизованная база данных — реестр
Введение
Для работы с важными системными ресурсами ОС Windows создает объекты, управление которыми осуществляет менеджер объектов. Когда приложение открывает файл, создает поток или семафор, оно получает описатель ( handle ) соответствующего объекта (см.
рис.
4.1). Например, после выполнения программного оператора
hSemaphore = CreateSemaphore(NULL, 0, MaxCount, "MySemaphore");
создающего семафор, возвращаемый описатель hSemaphore необходим приложению для последующей работы с этим семафором.
Рис.
4.1.
Создание объекта «семафор» приложением
В данном разделе дается краткое описание того, как функционирует менеджер объектов. С объектами придется сталкиваться на протяжении всего курса. Объекты — абстрактная концепция, которая активно используется в ОС Windows для регулирования доступа к системным ресурсам.
Наличие объектов является несомненным достоинством системы. Во-первых, это единый интерфейс ко всем системным ресурсам и структурам данных, таким, как процессы, потоки, семафоры и т.д. Именование объектов и доступ к ним осуществляются по одной и той же схеме. Использование объектов дает Microsoft возможность обновлять функциональность системы, не затрагивая программного интерфейса приложений. Во-вторых, это очень удобно с точки зрения системной безопасности. Каждый объект имеет список прав доступа, который проверятся каждый раз, когда приложение создает свой описатель объекта. Соответственно, все проверки, связанные с защитой, могут быть выполнены в одном модуле — диспетчере объектов (в соответствии с требованиями безопасности), с гарантией, что ни один процесс не может их обойти. Наконец, легко организовать совместный доступ к объектам, несложно отследить объекты, которые больше не используются, и т.д.
Объекты присутствуют почти во всех компонентах системы, особенно там, где есть данные, которые нужно разделять, защищать, именовать или сделать доступными. Например, посредством объектов реализованы программные и аппаратные прерывания, а также многие другие функции ядра. Некоторые объекты доступны пользовательским приложениям через вызовы Win32. Поэтому иногда ОС Windows называют объектно-ориентированной системой, — так, доступ к ресурсу возможен только через методы соответствующего объекта (инкапсуляция данных). Вместе с тем в данной схеме отсутствуют наследование и полиморфизм, поэтому ОС Windows нельзя считать объектно-ориентированной в строгом смысле этого слова.
Объекты ядра
В рамках данного курса нам придется активно использовать объекты, называемые в руководствах по Win32-программированию объектами ядра (kernel objects). Поддержка объектов ядра осуществляется собственно ядром и исполнительной системой. Помимо объектов ядра имеются также объекты, предназначенные для управления окнами (User), и объекты, предназначенные для управления графикой (GDI). Изучение этих категорий объектов, реализуемых подсистемой поддержки окон и графики и ориентированных на разработку графических интерфейсов пользователя, выходит за пределы данного курса.
К сожалению, понятие «объект ядра» имеет разный смысл у разных авторов (ср., например, это понятие в MSDN или в
[
Рихтер
]
, c одной стороны, и в
[
Руссинович
]
— с другой), поэтому для дальнейшего изложения потребуется уточнение терминологии.
Дело в том, что совокупность объектов образует слоеную структуру. Ядро поддерживает базовые объекты двух видов: объекты диспетчера (события, мьютексы, семафоры, потоки ядра, таймеры и др.) и управляющие (DPC, APC, прерывания, процессы, профили и др.) Более подробно эти внутриядерные объекты описаны в
[
Руссинович
]
.
Над объектами ядра находятся объекты исполнительной системы, каждый из которых инкапсулирует один или более объектов ядра. Объекты исполнительной системы предназначены для управления памятью, процессами и межпроцессным обменом. Они экспортируются в распоряжение пользовательских приложений через Win32 функции. К ним относятся такие объекты, как: процесс, поток, открытый файл, семафор, мьютекс, маркер доступа и ряд других. Полный список можно увидеть в MSDN. Эти объекты и называются объектами ядра в руководствах по программированию.
Внешнее отличие объектов ядра (объектов исполнительной системы) от объектов User и GDI состоит в наличии у первых атрибутов защиты, которые являются одним из параметров, создающих объект ядра функций.
Далее эти объекты ядра (объекты исполнительной системы) будут называться просто объектами.
Объект представляет собой блок памяти в виртуальном адресном пространстве ядра. Этот блок содержит информацию об объекте в виде структуры данных (см. ниже «структура объекта»). Структура содержит как общие, так и специфичные для каждого объекта элементы. Объекты создаются в процессе загрузки и функционирования ОС и теряются при перезагрузке и выключении питания.
Содержимое объектов доступно только ядру, приложение не может модифицировать его непосредственно.
Доступ к объектам можно осуществить только через его функции-методы (инкапсуляция данных), которые инициируются вызовами некоторых библиотечных Win32-функций.
Структура объекта. Методы объекта
Рис.
4.2.
Структура объекта
Как показано на
рис.
4.2, каждый объект имеет заголовок с информацией, общей для всех объектов, а также данные, специфичные для объекта. Например, в поле заголовка имеется список процессов, открывших данный объект, и информация о защите, определяющая, кто и как может использовать объект.
Счетчик ссылок на объект увеличивается на 1 при открытии объекта и уменьшается на 1 при его закрытии. Значение счетчика ссылок, равное нулю, означает, что объект больше не используется и выделенное ему адресное пространство ядра может быть освобождено. Наличие счетчика означает, что даже после завершения процесса, создавшего объект, этот объект может не быть разрушен (если его счетчик не обнулен).
Квота устанавливает ограничения на объемы ресурсов. Несмотря на то, что в ОС Windows реализован код для отслеживания квот, в настоящее время квоты не применяются и существуют достаточно мягкие ограничения. Например, по умолчанию лимит на открытые объекты для процесса — 230. Множество объектов делится на типы, а у каждого из объектов есть атрибуты, неизменные для объектов данного типа. Ссылка на тип объекта также входит в состав заголовка. Поля имя объекта и каталог будут описаны в разделе «именование объектов».
Методы объекта
В состав компонентов объекта типа входит атрибут методы — указатели на внутренние процедуры для выполнения стандартных операций. Методы вызываются диспетчером объектов при создании и уничтожении объекта, открытии и закрытии описателя объекта, изменении параметров защиты. Система позволяет динамически создавать новые типы объектов. В этом случае предполагается регистрация его методов у диспетчера объектов. Например, метод open вызывается всякий раз, когда создается или открывается объект и создается его новый описатель.
Описатели объектов
Создание новых объектов, или открытие по имени уже существующих, приложение может осуществить при помощи Win32-функций, таких, как CreateFile, CreateSemaphore, OpenSemaphore и т.д. Это библиотечные процедуры, за которыми стоят сервисы Windows и методы объектов. В случае успешного выполнения создается 64-битный описатель в таблице описателей процесса в памяти ядра. На эту таблицу есть ссылка из блока управления процессом EPROCESS (см.
«Реализация процессов и потоков»
).
Из 64-х разрядов описателя 29 разрядов используются для ссылки на блок памяти объекта ядра, 3 — для флагов, а оставшиеся 32 — в качестве маски прав доступа. Маска прав доступа формируется на этапе создания или открытия объекта, когда выполняется проверка разрешений. Таким образом, описатель объекта — принадлежность процесса, создавшего этот объект. По умолчанию он не может быть передан другому процессу. Тем не менее, система предоставляет возможность дублирования описателя и передачи его другому процессу специальным образом (см. ниже раздел «Совместное использование объектов» и часть IV «Безопасность«).
Рис.
4.3.
Объекты и их описатели
Win32-функции, создающие объект, возвращают приложению не сам описатель, а индекс в таблице описателей, то есть малое число: типа 1,2 а не 64-разрядное (см.
рис.
4.3). Впоследствии это значение передается одной из функций, которая принимает описатель объекта в качестве аргумента. Одной из таких функций является функция CloseHandle, задача которой — закрыть объект. Во избежание утечки памяти всегда рекомендуется закрывать объект, если в нем отпала надобность. Впрочем, по окончании работы процесса система закрывает все его объекты. Таким образом, структуры объектов ядра доступны только ядру, приложение не может самостоятельно найти эти структуры в памяти и напрямую модифицировать их содержимое.
Именование объектов. Разделяемые ресурсы
Многие объекты в системе имеют имена. Именование объектов удобно для учета объектов и поиска нужного объекта. Кроме того, знание имени объекта может быть использовано процессом для получения к нему доступа (совместное использование ресурсов). Пространство имен объектов по аналогии с пространствами имен реестра и файлов организовано в виде древовидной иерархической системы. В качестве нетерминальной вершины дерева используется объект — «каталог объектов». Каталог включает информацию, необходимую для трансляции имен объектов в указатели на сами объекты. Вследствие необходимости выполнения навигации по каталогам ссылка на объект по имени работает существенно дольше, чем по описателю.
«Увидеть» пространство имен можно только при помощи специальных инструментальных средств, например, с помощью утилиты winobj, входящей в состав MS Platform SDK. Другую версию этой утилиты можно бесплатно получить на сайте http://www.sysinternals.com.
Рис.
4.4.
Окно утилиты winobj
Ядро ОС — часть ОС, рационально размещаемая в ОЗУ, которая работает в привилегированном режиме и выполняет следующие функции:
— Управление и синхронизация процессов.
— Управление памятью.
— Диспетчеризация.
— Управление файловой системой, прерываниями, IO и т.д.
Доступ к функциям ядра ОС осуществляется через прерывания:
— программные
— аппаратные
Вход в ядро осуществляется по прерываниям. Когда ядро реагирует на данное прерывание, оно запрещает другие (если ядро не реентерабельно). После идентификации поступившего прерывания, ядро передает его обработчику – специальному системному процессу. Запрет прерываний обеспечивает предотвращение повторного входа в нереентерабельное ядро.
Нереентерабельность функций ДОС связана тем, что при повторном вхождении в эти функции в качестве СТЕКА используется одна и та же области памяти, в результате чего происходит зависание системы из-за порчи стека. Для преодоления этого недостатка необходимо перед каждой попыткой использования функций ДОС прерывающим процессом (работа с файловой системой, получение системных даты и времени, потоковый ввод/вывод, запуск процессов и др.) проверять, не используются ли эти функции в данный момент времени прерванным процессом. Об этом сигнализирует специальный критический флаг — внутренняя ячейка памяти ДОС. Если этот флаг установлен (не равен нулю), то ДОС уже находится в своем критическом участке, и повторный вызов функций ДОС запрещен. Если флаг сброшен (равен нулю), то функциями ДОС пользоваться можно.
В ОС реального времени ядро реентерабельное, т.е. допускает повторное вхождение в свой код.
Объекты ядра.
Объект – блок памяти, выделенный ядром для своих целей и доступный только ядру.
Объект ядра содержит имя объекта, класс защиты объекта, счётчик количества пользователей и другую информацию (смещение при открытии файла и т.д.).
Все объекты имеют описатели (Handle). Большинство объектов обладают свойством наследования.
Объекты ядра Windows:
— Процесс, поток.
— Файловый объект – открытый файл.
— Проекция файла на память.
— Событие, Семафор, Мьютекс.
— Почтовый ящик, канал, сокет и т.д.
ОС ведет учет объектов и управляет ими. Пользователь может запросить информацию об объекте.
Объекты можно создавать, уничтожать, открывать и закрывать посредством системных вызовов ОС по просьбе внешней программы. Созданные объекты закрепляются (принадлежат) создавшим их процессам. При порождении дочернего процесса, объекты ядра (как правило) наследуются из родительского, при этом создается копия объекта, принадлежащая уже дочернему процессу. Например, так наследуются стандартные потоки в/в, открытые файлы, каналы, семафоры и др. Номер дескриптора при наследовании сохраняется.
Микроядро отличается от обычного ядра тем, что в нем содержится основные, более общие функции управления ОС, а остальные функции ОС вынесены в отдельные процессы (приложения пользовательского уровня). Благодаря чему разработчик ОС может легко добавлять к ОС новые функции и расширять существующие. Таким образом, обеспечивается более эффективная защита ядра, более высокая производительность (микроядро может быть целиком размещено в кэш процессора). Микроядро изолирует все Машинно-зависимые команды, содержит ограниченный набору услуг с малым количеством системных функций (при переносе ОС на другую аппаратную платформу нужно переработать только микроядро, а все остальное – только перекомпилировать). Следовательно, обеспечивается переносимость, расширяемость и надежность.
Пример – ОС QNX, Win-NT (HAL-аналог микроядра).
1. Объекты ядра
Для работы с важными системными ресурсами ОС Windows создает объекты,
управление которыми осуществляет менеджер объектов.
• Ядро поддерживает базовые объекты двух видов: объекты диспетчера
(события, мьютексы, семафоры, потоки ядра, таймеры и др.) и управляющие
(DPC, APC, прерывания, процессы, профили и др.)
• Над объектами ядра находятся объекты исполнительной системы, каждый из
которых инкапсулирует один или более объектов ядра. Объекты
исполнительной системы предназначены для управления памятью, процессами
и межпроцессным обменом. К ним относятся такие объекты, как: процесс, поток,
открытый файл, семафор, мьютекс, маркер доступа и ряд других (MSDN). Эти
объекты и называются объектами ядра в руководствах по программированию.
1
2. Объекты ядра
• Внешнее отличие объектов ядра (объектов исполнительной
системы) от объектов User и GDI состоит в наличии у первых
атрибутов защиты, Далее эти объекты ядра (объекты
исполнительной системы) будут называться просто
объектами.
• Объект представляет собой блок памяти в виртуальном
адресном пространстве ядра. Этот блок содержит
информацию об объекте в виде структуры данных. Структура
содержит как общие, так и специфичные для каждого объекта
элементы. Объекты создаются в процессе загрузки и
функционирования ОС и теряются при перезагрузке и
выключении питания.
• Содержимое объектов доступно только ядру, приложение не
может модифицировать его непосредственно. Доступ к
объектам можно осуществить только через его функцииметоды (инкапсуляция данных), которые инициируются
вызовами некоторых библиотечных Win32-функций.
2
3. Создание и мониторинг объектов ядра
void __fastcall TForm1::SmCreateClick(TObject *Sender)
{ try {
HANDLE r=CreateSemaphore(NULL,1,5,»MySem»);
if (r) {AnsiString msg=»Semaphore was created»;
LBConsole->Items->Add(msg);} else
LBConsole->Items->Add(«Error»);
} catch ( … ) { }
}
void __fastcall TForm1::SmOpenClick(TObject *Sender)
{ try
{HANDLE r=OpenSemaphore(SEMAPHORE_ALL_ACCESS, false,»MySem»);
if (r) {
AnsiString msg=»Semaphore was opened.»;
LBConsole->Items->Add(msg);
} else
LBConsole->Items->Add(«Error opended»);
}
catch ( … ) {}
}
Приложение SemExample
3
Приложение Winobj
4. Структура объекта. Методы объекта
• Каждый объект имеет заголовок с информацией, общей для всех объектов, а
также данные, специфичные для объекта. Например, в поле заголовка имеется
список процессов, открывших данный объект, и информация о защите,
определяющая, кто и как может использовать объект.
• Счетчик ссылок на объект увеличивается на 1 при открытии объекта и
уменьшается на 1 при его закрытии.
4
5. Структура объекта. Методы объекта
Квота устанавливает ограничения на объемы ресурсов.
Например, по умолчанию лимит на открытые объекты для
процесса — 230. Множество объектов делится на типы, а у
каждого из объектов есть атрибуты, неизменные для
объектов данного типа. Ссылка на тип объекта также входит в
состав заголовка.
В состав компонентов объекта типа входит атрибут методы указатели на внутренние процедуры для выполнения
стандартных операций. Методы вызываются диспетчером
объектов при создании и уничтожении объекта, открытии и
закрытии описателя объекта, изменении параметров защиты.
Система позволяет динамически создавать новые типы
объектов. В этом случае предполагается регистрация его
методов у диспетчера объектов. Например, метод open
вызывается всякий раз, когда создается или открывается
объект и создается его новый описатель.
5
6. Описатели объектов
SemExample
WinObj
ProcExp
•Создание новых объектов, или открытие по имени уже существующих,
приложение может осуществить при помощи Win32-функций, таких, как
CreateFile, CreateSemaphore, OpenSemaphore и т.д.
•Это библиотечные процедуры, за которыми стоят сервисы Windows и методы
объектов. В случае успешного выполнения создается 64-битный описатель в
таблице описателей процесса в памяти ядра. На эту таблицу есть ссылка из
блока управления процессом EPROCESS
6
7. Процессы и потоки в ОС Windows
Для описания процесса ОС поддерживает набор структур,
главную из которых принято называть блоком управления
процессом (PCB, Process control block). Состав PCB:
• идентификатор процесса;
• токен доступа — исполняемый объект, содержащий
информацию о безопасности;
• базовый приоритет — основа для исполнительного приоритета
нитей процесса;
• процессорная совместимость — набор процессоров, на которых
могут выполняться нити процесса;
• предельные значения квот — максимальное количество
страничной и нестраничной системной памяти, дискового
пространства, предназначенного для выгрузки страниц,
процессорного времени — которые могут быть использованы
процессами пользователя;
• время исполнения — общее количество времени, в течение
которого выполняются все нити процесса.
7
8. Внутреннее устройство процессов в ОС Windows
ProcExp
Блок управления процессом (PCB) реализован в виде набора связанных
структур, главная из которых называется блоком процесса EPROCESS.
8
9. Создание процесса
Обычно процесс создается другим процессом вызовом Win32-функции
CreateProcess. Создание процесса осуществляется в несколько этапов:
1) на диске отыскивается нужный файл-образ, после чего создается объект
«раздел» памяти для проецирования на адресное пространство нового
процесса (kernel32.dll);
2) выполняется обращение к системному сервису NtCreateProcess для
создания объекта «процесс». Формируются блоки EPROCESS, KPROCESS и
блок переменных окружения PEB. Менеджер процессов инициализирует в
блоке процесса маркер доступа (копируя аналогичный маркер
родительского процесса), идентификатор и другие поля;
3) создание первичного потока (сервис NtCreateThread,
библиотека
kernel32.dll);
4) kernel32.dll посылает подсистеме Win32 сообщение, которое содержит
информацию, необходимую для выполнения нового процесса. Данные о
процессе и потоке помещаются, в список процессов и список потоков
данного процесса, затем устанавливается приоритет процесса, создается
структура, используемая частью Win32, которая работает в режиме ядра, и
т.д.;
5) запускается первичный поток, для чего формируются его начальный
контекст и стек, и выполняется запуск стартовой процедуры потока
режима ядра KiThreadStartup. После этого стартовый код из библиотеки
C/C++ передает управление функции main() запускаемой программы.
9
10. Создание процесса. Функция CreateProcess
BOOL CreateProcess(
PCTSTR pszApplicationName, //имя программы;
PTSTR pszCommandLine, //параметры командной строки;
SECURITY_ATTRIBUTES psaProcess, //атрибуты безопасности процесса;
PSECURITY_ATTRIBUTES psaThread, //атрибуты безопасности главного потока;
BOOL bInheritHandles, //- если bInheritHandles == TRUE, то созданный процесс
(запущенная программа), наследует дескрипторы (handles) запускающей
программы;
DWORD fdwCreationFlags, //- параметры создания. Здесь можно указать класс
приоритета создаваемого процесса и некоторые дополнительные параметры;
PVOID pvEnvironment, // — указатель на блок окружения или NULL, тогда
используется блок окружения родителя;
PCTSTR pszCurDir, // текущая директория или NULL, тогда используется текущая
директория родителя;
PSTARTUPINFO psiStartInfo, //- указатель на структуру STARTUPINFO, которая
определяет положение главного окна;
PPROCESS_INFORMATION ppiProcInfo //информация о созданном процессе.
);
10
11. Создание процесса (пример)
#include <windows.h>
#include <stdio.h>
void main( VOID )
{
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcInfo;
TCHAR CommandLine[] = TEXT(“format c:»);
ZeroMemory( &StartupInfo, sizeof(StartupInfo) );
StartupInfo.cb = sizeof(StartupInfo);
ZeroMemory( &ProcInfo, sizeof(ProcInfo) );
if( !CreateProcess( NULL, // Не используется имя модуля
CommandLine,
// Командная строка
NULL,
// Дескриптор процесса не наследуется.
NULL,
// Дескриптор потока не наследуется.
FALSE,
// Установка описателей наследования
0,
// Нет флагов создания процесса
NULL,
// Блок переменных окружения родит. процесса
NULL,
// Использовать текущий каталог родит. процесса
&StartupInfo,
// Указатель на структуру STARTUPINFO.
&ProcInfo )
// Указатель на структуру информации о процессе.
)
}
11
printf( «CreateProcess failed.» );
// Ждать окончания дочернего процесса
WaitForSingleObject( ProcInfo.hProcess, INFINITE );
// Закрыть описатели процесса и потока
CloseHandle( ProcInfo.hProcess );
CloseHandle( ProcInfo.hThread );
Приложение createprocess
12. Получение идентификатора процесса
procedure TForm1.Button1Click(Sender: TObject);
var
han : THandle;
pi : TProcInfo; // from «tlhelp32» in uses clause
sID : string;
begin
LB.Items.Clear;
// Get a snapshot of the system
han := CreateToolhelp32Snapshot( TH32CS_SNAPALL, 0 );
if han = 0 then exit;
pi:=TProcInfo.Create;
pi.ProcStruct.dwSize := sizeof( PROCESSENTRY32 );
if Process32First( han, pi.ProcStruct ) then
repeat
sID := ExtractFileName( pi.ProcStruct.szExeFile );
while length(sID)<50 do sID:=sId+’ ‘; sID:=sID+’|’;
sID:=sID+’ ‘+IntToStr(pi.ProcStruct.th32ProcessID);
LB.Items.AddObject(sId,pi);
pi:=TProcInfo.Create;
pi.ProcStruct.dwSize := sizeof( PROCESSENTRY32 );
until not Process32Next( han, pi.ProcStruct);
end;
Приложение WinProcList
12
Объекты ядра используются системой и нашими приложениями для управления множеством разных ресурсов: процессами, потоками, файлами и т.д.
Система позволяет создавать и оперировать несколькими типами таких объектов, в том числе: маркерами доступа (access token objects), файлами (file objects), проекциями файлов (file-mapping objects), портами завершения ввода вывода (I/O completion port objects), заданиями (jobs), почтовыми ящиками (mailslot objects), мьютексами (mutex objects), каналами (pipe objects), процессами (thread objects) и ожидаемыми таймерами (waitable timer objects).
Эти объекты создаются Windows-функциями. Например, CreateFileMapping заставляет систему сформировать объект проекцию файла. Каждый объект ядра на самом деле просто блок памяти, выделенный ядром и доступный только ему.
Блок представляет собой структуру данных, в элементах которой содержится информация об объекте. Некоторые элементы (дескриптор защиты, счетчик числа пользователей и др.) присутствуют во всех объектах, но большая их часть специфична для объектов конкретного типа. Например, у объекта процесс есть идентификатор, базовый приоритет и код завершения, а у объекта файл — смещение в байтах, режим разделения и режим открытия.
Приложение не может напрямую обращаться к объектам ядра читать и изменять их содержимое.
Для взаимодействия с объектами ядра у Windows предусмотрен набор функций, обрабатывающих структуры объектов ядра по строго определенным правилам. Когда мы создаем объект ядра, функция возвращает описатель идентифицирующий созданный объект (HANDLE). Все операции с текущим объектом ядра возможны только при указании этого описателя управляющей функции.
Для большей защиты, описатели уникальны только внутри конкретного процесса. Поэтому, передавая по межпроцессорной связи описатель объекта другому процессу, используя описатель в другом процессе, мы получим ошибку. Это ограничение можно обойти, но об этом позже.
Учет пользователей объектов ядра.
Объекты ядра принадлежат ядру, а не процессу. Это говорит о том, что завершая работу с процессом, мы не обязательно разрушаем объект ядра. В большинстве случаев объект разрушается, но если созданный вами объект ядра используется другим процессом, ядро запретит разрушение объекта до тех пор, пока от него не откажется последний пользователь.
В каждом объекте, как уже говорилось, есть счетчик пользователей объектом. В момент создания счетчику присваивается значение 1. Соответственно, при обращении к нему другого процесса, счетчик увеличивается на 1. Когда пользовательский процесс завершается, счетчик уменьшается. Система удаляет объект ядра, когда счетчик обнуляется.
Почти во всех функциях, создающих объекты, есть параметр SECURITY_ATTRIBUTES. Он необходим для защиты объектов ядра от несанкционированного доступа. Чаще всего это свойство используют в серверных приложениях, в клиентских приложениях этот объект можно игнорировать.
Если вы пишете для win98, то там такое свойство отсутствует, но для корректной работы таких приложений в Win2000 и выше, стоит помнить о работе с соответствующими механизмами.
При передаче в таком атрибуте NULL большинство объектов будут созданы со стандартными свойствами защиты, когда к объекту допускаются: создатель и администраторская группа. Остальные игнорируются.
Более подробно о защите объектов ядра в следующий раз.