<<
>>

Реализация процессов и потоков

В этом разделе мы более подробно рассмотрим то, как в Windows создается процесс (и начальный поток). Поскольку Win32 является самым документированным интерфейсом, то начнем именно с него.
Однако мы быстро спустимся вниз в ядро и разберемся в реализации вызова собственного API (для создания нового процесса). Мы сосредоточимся на главных путях выполнения кода при создании процессов. Также рассмотрим подробности, которые помогут заполнить пробелы в том, что мы рассказали до настоящего момента.

Процесс создается тогда, когда другой процесс делает вызов CreateProcess интерфейса Win32. Этот вызов запускает процедуру (пользовательского режима) из kernel.dll, которая осуществляет вызов NtCreateUserProcess в ядре, чтобы за несколько этапов создать процесс:

1. Преобразуется имя исполняемого файла (заданное в виде параметра) из маршрута Win32 в маршрут NT. Если исполняемый файл имеет только имя (без маршрута в виде каталогов), то его поиск ведется в тех каталогах, которые перечислены в качестве каталогов по умолчанию (они включают и те, которые содержатся в переменной окружения PATH, но не только их).

2. Собираются все параметры создания процесса и передаются (вместе с полным маршрутом к исполняемой программе) собственному интерфейсу NtCreateUserProcess.

3. Работая в режиме ядра, NtCreateUserProcess обрабатывает параметры, а затем открывает образ программы и создает объект сегмента, который может использоваться для отображения программы на виртуальное адресное пространство нового процесса.

1. Диспетчер процессов выделяет и инициализирует объект процесса (структуру данных ядра, представляющую процесс как для ядра, так и для исполнительного уровня).

2. Диспетчер памяти создает адресное пространство для нового процесса, выделяя и инициализируя каталоги страниц и дескрипторы виртуальных адресов, описывающие режим ядра, в том числе специфичные для процесса области, такие как элементы каталога страниц self-map, которые дают каждому процессу доступ в режиме ядра к физическим страницам всей таблицы страниц при помощи виртуальных адресов ядра.

Мы опишем self-map более подробно в разделе 11.5.

3. Для нового процесса создается таблица описателей, в которую дублируются все те описатели вызвавшей стороны, для которых разрешается наследование.

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

5. Исполнительный уровень создает и инициализирует блок Process Environment Block (PEB) пользовательского режима, который используется как пользовательским режимом, так и ядром для поддержания информации о состоянии процесса (например, указатели кучи пользовательского режима и список загруженных библиотек (DLL).

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

7. Из специальной таблицы описателей (которую поддерживает ядро для эффективного выделения локально-уникальных идентификаторов процессов и потоков) выделяется идентификатор процесса.

8. Выделяется и инициализируется объект потока. Выделяется стек пользовательского режима и блок Thread Environment Block (TEB). Инициализируется запись CONTEXT, которая содержит начальные значения регистров процессора для потока (в том числе указатели команд и стека).

9. Объект процесса добавляется в глобальный список процессов. В таблице описателей вызвавшей стороны выделяется место под описатели для объектов процесса и потока. Для начального потока выделяется идентификатор (из таблицы идентификаторов).

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

11. Если интерфейс NT API дает сбой, то код Win32 проверяет, не принадлежит ли данный процесс к другой подсистеме (например, WOW64).

Или, возможно, данная программа помечена для выполнения под управлением отладчика. Эти специальные случаи обрабатываются специальным кодом пользовательского режима в CreateProcess.

12. Если NtCreateUserProcess отработал успешно, то нужно сделать еще кое-что. Процессы Win32 нужно зарегистрировать в процессе csrss.exe подсистемы Win32. Kernel32.dll посылает сообщение в csrss, которое сообщает ему о новом процессе (а также передает описатели процесса и потока, чтобы он мог себя сдублировать). Процесс и потоки вносятся в таблицы подсистемы (чтобы там имелся полный список всех процессов и потоков Win32). Затем подсистема показывает курсор (указатель с песочными часами), чтобы сообщить пользователю о том, что в данный момент что-то происходит, но курсор все же можно использовать. Когда процесс делает свой первый вызов графического интерфейса пользователя (обычно это делается для создания окна), то курсор исчезает (если нет других вызовов) — тайм-аут у него 2 с.

13. Если процесс ограничен (как имеющий низкие права Internet Explorer), то маркер модифицируется для ограничения доступа к объектам из нового процесса.

14. Если приложение было помечено как подлежащее исправлению (shimmed) для совместимой работы в текущей версии Windows, то применяются указанные исправления (shims). Исправления обычно заключают в оболочку вызовы библиотек, чтобы модифицировать их поведение, например вернуть фальсифицированный номер версии или отложить освобождение памяти.

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

В ранних версиях Windows основная часть алгоритма создания процесса была реализована в процедуре пользовательского режима, которая должна была создавать новый процесс при использовании нескольких системных вызовов и за счет выполнения другой работы с помощью исходных API-интерфейсов NT, поддерживающих реализацию подсистем. Эти действия были перенесены в ядро, чтобы ограничить возможность родительского процесса манипулировать дочерним процессом в случаях, когда дочерний процесс выполняет защищенную программу, например программу, реализующую DRM для защиты фильмов от пиратства.

Исходная API-функция NtCreateProcess по-прежнему поддерживается системой, поэтому основная часть создания процесса может все еще осуществляться в пользовательском режиме родительского процесса, если только создаваемый процесс не является защищенным.

<< | >>
Источник: Э. ТАНЕНБАУМ Х. БОС. СОВРЕМЕННЫЕ ОПЕРАЦИОННЫЕ СИСТЕМ Ы 4-е ИЗДАНИЕ. 2015

Еще по теме Реализация процессов и потоков:

  1. коян: Восходящий узел - включение в общий поток; Нисходящий узел - исключение из общего потока.
  2. ПОТОК СОЗНАНИЯ
  3. Альбатрос (восхождение на поток)
  4. ТЕОРИЯ ПОТОКА СОЗНАНИЯ
  5. 3.9. ПОТОК СОЗНАНИЯ
  6. 2.2.1. Поток образов
  7. Глава 3. ОТКРОЙТЕ СВОЙ ПОТОК ОБРАЗОВ
  8. 12.2.1. Групповой поток образов
  9. МИХАЙ ЧИКСЕНТМИХАЙИ. В ПОИСКАХ ПОТОКА, 2015
  10. 13.5.1. Игра в поток образов
  11. 2.7. КАК ВЫЗВАТЬ ПОТОК ОБРАЗОВ
  12. 12.3.2. Сценарий группового потока образов
  13. 3.10. ТИПИЧНЫЙ ПОТОК ОБРАЗОВ
  14. 4.16. ПОТОК ОБРАЗОВ - ЭТО НЕ ГИПНОЗ
  15. 6.14. ЧТО, ЕСЛИ ПОТОК ОБРАЗОВ ГОВОРИТ "НЕТ"?
  16. Очерк 2: Берт «Процесс — вот мое достояние. Именно процесс создает успех»
  17. Глава 6. Реализация права