Совместное использование статических данных несколькими экземплярами exe и dll модулей.

Например, имеется ехе файл, который состоит из

ехе файл виртуальная память ВАП

раздел кода 3 страницы   раздел данных 2 страницы
страница кода 2 страница кода 1 страница данных 2 страница кода 3 страница данных 1
/T JMm0w47lQ4sD3bdUf2wOzkCotrSvvmb1LHm7bjyl+4enRzTm8mK6uwUVaYp/MPzUl+pQSqedP7AN qjeQZssbQcVIM1ACLJOVCLtfQZeF/r+g/AYAAP//AwBQSwECLQAUAAYACAAAACEAtoM4kv4AAADh AQAAEwAAAAAAAAAAAAAAAAAAAAAAW0NvbnRlbnRfVHlwZXNdLnhtbFBLAQItABQABgAIAAAAIQA4 /SH/1gAAAJQBAAALAAAAAAAAAAAAAAAAAC8BAABfcmVscy8ucmVsc1BLAQItABQABgAIAAAAIQDe NcW5TgIAAFsEAAAOAAAAAAAAAAAAAAAAAC4CAABkcnMvZTJvRG9jLnhtbFBLAQItABQABgAIAAAA IQAQU1du3AAAAAkBAAAPAAAAAAAAAAAAAAAAAKgEAABkcnMvZG93bnJldi54bWxQSwUGAAAAAAQA BADzAAAAsQUAAAAA " o:allowincell="f"/>
страница кода 1 страница кода 2 страница кода 3 страница данных 1 страница данных 2
M dYtWh5kbkNj7dN7qyKdvpPH6yOG2l5dJci2t7og/tHrAhxbrr+1oFWzWy1X+thqn2n88ps+7l/XT e8iVOj+b7u9ARJziHwy/9bk6VNxp70YyQfQKsjxJGWUj4wkMXCW3NyD2LMyzOciqlP8nVD8AAAD/ /wMAUEsBAi0AFAAGAAgAAAAhALaDOJL+AAAA4QEAABMAAAAAAAAAAAAAAAAAAAAAAFtDb250ZW50 X1R5cGVzXS54bWxQSwECLQAUAAYACAAAACEAOP0h/9YAAACUAQAACwAAAAAAAAAAAAAAAAAvAQAA X3JlbHMvLnJlbHNQSwECLQAUAAYACAAAACEAS2ksRGUCAACCBAAADgAAAAAAAAAAAAAAAAAuAgAA ZHJzL2Uyb0RvYy54bWxQSwECLQAUAAYACAAAACEAQVYUWeEAAAAKAQAADwAAAAAAAAAAAAAAAAC/ BAAAZHJzL2Rvd25yZXYueG1sUEsFBgAAAAAEAAQA8wAAAM0FAAAAAA== " o:allowincell="f">

рис. 1.

Допустим загружен второй экземпляр этого же процесса. Информация о предоставляемой файлом страницы виртуальной памяти хранится в структурах, которые называются модули. Допустим процесс 1 изменяет данные на странице данных 2. Windows NT, Windows 2000 выделяет дополнительные страницы из страничного файла по мере необходимости, благодаря тому, что Windows NT, 2000 имеют такой атрибут страницы, как PAGE_WRITECOPY. В Windows 95, 98 такого атрибута нет. Поэтому Windows 95, 98 резервирует в страничный файл количество страниц, необходимых для размещения блока глобальных переменных, то есть реально используются, если программа изменяет глобальные переменные.

Иерархия функций работы с памятью.

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

1. Функции управления памятью на уровне системных сервисов – 0 кольцо. В Windows 95, 98 это VMM.vxd, в Windows NT, 2000 – это ntoskrnl.exe. Эти функции предназначены для выделения небольших областей памяти и манипулирования страницами этих областей, то есть единица выделения – это страница. Прикладные программы не имеют право вызывать эти функции.

2. VirtualXXX. Это функции управления виртуальной памятью, поддерживаемые kernel32. Эти функции поддерживает ядро. По функциональным возможностям аналогичны функциям 1 уровня. Эти функции могут использоваться приложениями пользователей.

3. Функции для работы с кучей. Функции Win32API, поддерживается kernel32, позволяют выделять в память из кучи минимальный блок - 4 байта. По смыслу совпадают с функциями языков програм-мирования.

HeapXXX, new, malloc. Примыкают функции LocalHeap и GlobalHeap (устаревшие – используются для совместности и выполняют одинаковые действия).

4. Функции для работы с памятью конкретных языков программирования.

New, malloc.

12. Объекты ядра. Процессы, потоки и модули в Win32.

Объекты kernel32.dll.

Объекты kernel32 являются ключевыми структурами данных ОС и находятся в куче, которой владеет kernel32. Например, в Windows 95,98 около 17 объектов, в Windows 2000 около 26 объектов. Примеры объектов:

объект-процесс

объект-поток

объект-файл

объект-файл проецируемый в память

объект-семафор

объект-событие

объект-mutex

объект-почтовый слол

объект-сокет

объект-именованный программный канал

Такая структура как модули не является объектом ядра. Каждый объект ядра начинается с заголовка. Он состоит из нескольких полей.

1. Тип объекта. Заносится постоянная, характеризующая тип объекта. В зависимости от типа объекта интерпретируются другие поля.

2. Счётчик ссылок на объект. Определяет сколько раз программный код обращается к объекту. Когда оно станет равно 0, то ОС удаляет объект.

Модули – это версия в памяти кода данных и ресурсов исполняемого файла или dll. В каждом процессе имеется модуль для ехе файла, каждая dll – это модуль.

Процесс – есть субъект владения. Процесс владеет памятью, то есть своим ВАП. Владеет дескрипторами файлов, которые прикладная программа может использовать для чтения записи, владеет потоками, списками модулей, dll, которые необходимы процессу для работы. Процесс не представляет исполнение программного кода. За выполнение программного кода отвечают потоки. Каждый процесс связан с файлом на диске. Но файл становится процессом тогда, когда загружен в память на выполнение.

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

13. Модули Win32. База данных модуля. Глобальный список модулей (структуры IMTE) и локальный список модулей (структура MODREF). Связь между структурами MODREF и IMTE. Функции для работы с модулями.

Модули – это версия в памяти кода данных и ресурсов исполняемого файла или dll. В каждом процессе имеется модуль для ехе файла, каждая dll – это модуль.

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

Информация о модулях хранится в базе данных модуля. В Windows 95, 98, NT база данных модуля фактически представляет собой заголовок исполняемого файла. Любой процесс загружается в ВАП.

начало база данных

ехе файла модуля

При работе с модулями Win32 использует дескриптор модуля HMODULE.

GetModuleHandle(…) – получает дескриптор модуля, виртуальный адрес с которого загружается ехе или dll. Например для всех процессов, работающих под Windows 95, 98 это 00400000h.

База данных модуля находится в адресном пространстве процесса, кроме того, для оператив-ной работы с модулем W32 создаёт копию базы данных своей системной кучи.

ВАП

  ////////////////////////////////////////////////////////////////////////////   ////////////////////////////////////////////////////////////////////////////
файл на диске видны всем процессам

  база данных модуля

2 Гб

личная база данных модуля

начальный адрес

При работе с модулями возникают две проблемы:

1. Проблема защиты информации, то есть создание закрытого адресного пространства для каждого процесса.

2. Для оперативной работы ОС надо знать список всех загруженных модулей.

Эти проблемы решаются с помощью двух структур IMTE (Internal Module Table Entry) и MODREF – она поддерживает собственный список модулей для каждого процесса. И та и другая структуры находятся в системной куче ядра. Рассмотрим структуру IMTE.

Структура IMTE.

таблица модулей IMTE

kernel32.dll

pModuleTableArray

user32.dll
gdi32.dll
my.exe

Начало таблицы модулей хранится в pModuleTableArray. Как только новый процесс или dll создаются, то kernel32 создаёт структуру IMTE, ищет свободный элемент в таблице модулей и записывает в него указатель на структуру IMTE. ОС сама следит за тем, чтобы не произошло заполнение таблицы модулей. Структура:

· Указатель на базу данных модуля, расположенного в куче kernel32.dll в области выше 2 Гб. Благодаря указателю kernel32 может получать информацию о любом модуле не переключаясь в контекст памяти.

· Указатель на полное имя файла из которого был создан модуль. Память под полное имя модуля выделяется.

· Указатель на строку с именем модуля. Этот указатель указывает внутрь предыдущей структуры.

· Число символов в полном имени файла.

· Число символов только в имени файла.

Зачем нужны эти два предыдущих поля? Например, функция GetModuleHandle с помощью указателя просматривает структуры IMTE и для ускорения поиска сравнивает длины запрашиваемого модуля и модуля в очередной структуре IMTE, если длины не совпадают, то сравнивать имена смысла не имеет.

· Число разделов в модуле. Например, раздел, содержащий данные, программный код и т.д.

· Базовый адрес, по которому был запущен модуль.

· Счётчик ссылок к модулю.

· Счётчик числа ссылок в модуле, например, если какая-то программа была запущена на выполнение три раза, то для этой программы создаётся три объекта ядра процесса и одна база данных модуля.

Структура MODREF.

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

Структура MODREF создаётся для exe файла и для каждой dll, используемой файлом. Память для каждой MODREF выделяется из кучи kernel32.

Рассмотрим список MODREF для файла my.exe, который использует kernel32.dll и bar.dll.

PDB my.exe

pModuleTableArray Таблица модулей

MODREF

   
   
kernel32.dll

индекс в IMTE

E o4y7XifGpNphx3KhxYEeWqo+VntnIZRr2pVfs2pmNpeNp2T3+PyE1p6fTfd3oCJN8Q+GH31Rh0Kc tn7PdVC9ZJNeC2ohMQtQAiTp1S2o7W+ji1z/f6H4BgAA//8DAFBLAQItABQABgAIAAAAIQC2gziS /gAAAOEBAAATAAAAAAAAAAAAAAAAAAAAAABbQ29udGVudF9UeXBlc10ueG1sUEsBAi0AFAAGAAgA AAAhADj9If/WAAAAlAEAAAsAAAAAAAAAAAAAAAAALwEAAF9yZWxzLy5yZWxzUEsBAi0AFAAGAAgA AAAhAIz4wqtTAgAAYQQAAA4AAAAAAAAAAAAAAAAALgIAAGRycy9lMm9Eb2MueG1sUEsBAi0AFAAG AAgAAAAhAH/rqkTcAAAACgEAAA8AAAAAAAAAAAAAAAAArQQAAGRycy9kb3ducmV2LnhtbFBLBQYA AAAABAAEAPMAAAC2BQAAAAA= " o:allowincell="f"/>таблице

my.exe
2 2o54knLX6zRJMu2wY/nQ4kAPLdVf24MzEKp32lc/s3qWfCwbT+n+8fkJjbm+mu7vQEWa4jkMf/iC DqUw7fyBbVC9gXW6kKSBbA1K7HSZid7JsUpuQZeF/j+g/AUAAP//AwBQSwECLQAUAAYACAAAACEA toM4kv4AAADhAQAAEwAAAAAAAAAAAAAAAAAAAAAAW0NvbnRlbnRfVHlwZXNdLnhtbFBLAQItABQA BgAIAAAAIQA4/SH/1gAAAJQBAAALAAAAAAAAAAAAAAAAAC8BAABfcmVscy8ucmVsc1BLAQItABQA BgAIAAAAIQCpfoR+VgIAAGEEAAAOAAAAAAAAAAAAAAAAAC4CAABkcnMvZTJvRG9jLnhtbFBLAQIt ABQABgAIAAAAIQDMdBNU3QAAAAgBAAAPAAAAAAAAAAAAAAAAALAEAABkcnMvZG93bnJldi54bWxQ SwUGAAAAAAQABADzAAAAugUAAAAA " o:allowincell="f"/>
   
модулей

bar.dll
   

Структура MODREF содержит недокументированные поля:

1. Указатель на структуру PDB для обеспечения обратной связи.

2. Индекс в таблице модулей, то есть индекс в глобальной таблице модулей.

3. Указатель на следующую структуру MODREF.

Конец списка обозначается 00000000.

Все модуль-зависимые функции просматривают только структуры MODREF для конкретного процесса. Модуль-зависимые функции:

GetProcAddress(…) – получив идентификатор модуля и идентификатор функции (это её имя или порядковый номер экспорта) возвращает адрес точки входа этой функции.

GetModuleFileName(…) – по идентификатору модуля возвращает полный путь к exe или dll файлам.

GetModuleHandle(…) – по имени файла возвращает идентификатор этого модуля.

14. Процессы Win32. Идентификатор процесса и дескриптор процесса. Объект ядра процесс в Win32. Функции для работы с процессами Таблица дескрипторов процесса.

Процесс – есть субъект владения. Процесс владеет памятью, то есть своим ВАП. Владеет дескрипторами файлов, которые прикладная программа может использовать для чтения записи, владеет потоками, списками модулей, dll, которые необходимы процессу для работы. Процесс не представляет исполнение программного кода. За выполнение программного кода отвечают потоки. Каждый процесс связан с файлом на диске. Но файл становится процессом тогда, когда загружен в память на выполнение.

Для работы с процессом ОС создаёт структуру базы данных процесса. Эта база данных PDB. EPROCESS – управляющая структура (идентификатор).

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

TD

PDB
0

Идентификатор процесса является указателем на базу данных процесса. Функции Win32 для работы с процессами.

CreateProcess(…) – создаёт новый процесс.

ExitProcess(…) – завершает процесс с уведомлением всех подключенных dll.

TerminateProcess(…) – завершает процесс без уведомления подключенных dll.

GetProcessTimes(…) – получает временные параметры процесса. Определяет сколько времени в режиме ядра, а сколько в пользовательском режиме. В Windows 95, 98 функция не поддерживается.

GetCurrentProcess(…) – можно получить дескриптор текущего процесса.

GetCurrentProcessId(…) – можно получить идентификатор текущего процесса.

GetExitCodeProcess(…) – возвращает код завершения процесса.

GetCommandLine(…) – возвращает указатель на командную строку, переданную текущему процессу, то есть можно получить входные параметры с помощью неё.

GetEnvironmentString(…) – возвращает адрес блока переменных окружения.

Структуры данных процесса.

TEB
PEB

Адресное пространство

процесса

PDB

Блок процесса Win32
Системное адресное

пространство

TDB
Таблица дискрипторов

1 i87EmR+Q+PbhgzOJZWikDebI4a6X8yy7ls50xB9aM+B9i/XndnQaNuvlSr2uxqkO7w/50+55/fgW ldbnZ9PdLYiEU/ozww8+o0PFTHs/ko2iZ32jrtiqYZ7lINhwmSke9r8LWZXyf4PqGwAA//8DAFBL AQItABQABgAIAAAAIQC2gziS/gAAAOEBAAATAAAAAAAAAAAAAAAAAAAAAABbQ29udGVudF9UeXBl c10ueG1sUEsBAi0AFAAGAAgAAAAhADj9If/WAAAAlAEAAAsAAAAAAAAAAAAAAAAALwEAAF9yZWxz Ly5yZWxzUEsBAi0AFAAGAAgAAAAhAFyz9JljAgAAfQQAAA4AAAAAAAAAAAAAAAAALgIAAGRycy9l Mm9Eb2MueG1sUEsBAi0AFAAGAAgAAAAhAPcZ0UneAAAACQEAAA8AAAAAAAAAAAAAAAAAvQQAAGRy cy9kb3ducmV2LnhtbFBLBQYAAAAABAAEAPMAAADIBQAAAAA= " o:allowincell="f"> …

EB – Environment Block. PEB – блок окружения процесса. TEB – блок окр. потока. TDB – база данных потока. PDB – бд процесса.

PDB или EProcess содержат данные, необходимые ОС для управления процессом и указатели на некоторые доп. структуры.

Блок PDB.Дескрипторы виртуальных адресов – это структуры, описывающие распределение ВАП.Указатель на цепочку потоков данного процесса.Указатель на таблицу дескрипторов.Указатель на блок переменных окружения PEB.

Блок KPROCESS.Содержит доп. информацию:указатель на каталог страниц процесса, базовый приоритет по умолчанию.

Блок переменных окружения (PEB).Расположен в пользовательском адресном пространстве.В Windows 2000 находится по адресу 7FFDF000h. Содержит следующую информацию:Адрес кучи процесса по умолчанию.Указатель на структуры, описывающий загруженные модули.IMTE – описывает все загруженные модули всеми процессами.MODREF – содержит список всех модулей, используемых данным процессом.Содержит указатель на список файлов, которые используются данным процессом.Указатель на базу данных среды, которая содержит текущий каталог, область окружения процесса, командную строку.Указатель на заголовок списка свободного пространства в куче по умолчанию.Указатель на заголовок связанного списка куч процесса.

Таблица дескрипторов.

Таблица дескрипторов содержит не только дескрипторы файлов, но и объектов ядра. Структу-ра таблицы дескрипторов:

Количество записей 4байта
Флаг 1 8 байт
Объект 1
 
Флаг N 8 байт
Объект N

Первые 4 байта определяют количество записей в таблице дескрипторов (30h). Если таблица заполнена, то Windows создаёт кучу, делая прибавление 10h и так далее, то есть для Windows ограничения в 255 дескрипторов не существует. После количества записей идёт массив 8 байтных структур. Каждая структура состоит из двух полей.

1 поле. Флаг управления доступом к объекту. Назначение флагов различно для различных типов объекта. Например объект – процесс. Флаг – процесс завершён. Следующее DWORD – указатель базы данных соответствующего объекта.

Переменная ядра, связанная с процессами.PsActiveProcessHead. Заголовок списка блоков PDB. CreateProcess(…) открывет ехе файл, который будет выполняться в процессе, то есть PDB. Создаёт первичный поток, то есть стек потока, контекст потока (содержимое всех регистров) и объект поток, то есть TDB.

15. Потоки. Состояния потоков. Свойства потоков. Объект ядра поток. Функции для работы с потоками.

Потоки отвечают за исполнение программного кода. При создании процесса всегда создаётся первичный поток. По желанию программиста создаются дополнительные потоки. CreateThread(…). Для чего создаются потоки?

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

Поток может находится в одном из 3-х состояний:

1. Поток фактически работает, при этом в регистре процессора переписывается содержимое структуры CONTEXT. Все остальные потоки процесса приостанавливаются в случае одного процессора в системе.

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

3. Заблокированное состояние. Поток ожидает некоторого события, например, ожидание завершения работы другого потока или какого-либо процесса. До наступление этого события планировщик не позволит этому процессу выполнится.

Объектами синхронизации являются потоки процессы, критические секции, семафоры, события, мьютексы.

Потоки владеют набором регистров.

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

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

Поток может завладеть или освободить синхронизирующими объектами процесса. Дескриптор потока – это индекс в таблице дескрипторов процесса. Идентификатор потока – это закодированный указатель на базу данных потока (PDB).

Наши рекомендации