Песочница в Windows
Песочница — это новый легковесный инструмент в ОС Windows, позволяющий запускать приложения в безопасном изолированном окружении.
Случалось ли Вам оказаться в ситуации, когда необходимо запустить какую-то программу, но Вы не совсем уверены в источнике её происхождения? Или другой пример — необходимость проверить что-то на «чистой» версии Windows. Во всех подобных случаях раньше был только один выход — установить ОС на отдельную физическую или виртуальную машину и провести нужный эксперимент. Но это больше не так.
Microsoft разработал новый механизм под названием Песочница (eng. Windows Sandbox). Это изолированное временное окружение, в котором Вы можете запускать подозрительное программное обеспечение без риска навредить своему ПК. Любое ПО, установленное в Песочнице, остаётся только в Песочнице и не может взаимодействовать с основной ОС. Как только Вы закрываете Песочницу — всё её содержимое безвозвратно уничтожается.
Вот основные особенности Песочницы:
Системные требования
Быстрый старт
1. Установите Windows 10 Pro или Enterprise, билд 18305 или выше
2. Включите виртуализацию:
3. Откройте (через Панель Управления) список установленных компонентов Windows и включите в нём Песочницу. Нажмите ОК. Если увидите запрос на перезагрузку компьютера — подтвердите его.
4. Запустите Песочницу из меню Пуск. Разрешите повышение прав для её процесса.
5. Скопируйте (через буфер обмена) в Песочницу бинарник, который хотите запустить.
6. Запустите бинарник в Песочнице. Если это инсталлятор — пройдите процедуру установки и запустите установленное приложение.
7. Используйте приложение по назначению.
8. Когда закончите — просто закройте Песочницу. Всё её содержимой будет удалено.
9. Опционально — можете убедиться, что в Вашей основной ОС ничего не изменилось.
Что под капотом у Песочницы
Песочница Windows построена на технологии, которая называется Windows Containers. Контейнеры разрабатывались (и давно используются) для работы в облаке. Microsoft взял уже достаточно зрелую и протестированную технологию и доработал её для пользователей десктопной Windows.
Среди ключевых адаптаций можно отметить:
Динамически генерируемый образ
Песочница является хотя и легковесной, но всё же виртуальной машиной. И, как любой виртуальной машине, ей требуется образ, с которого она может загрузится. Важнейшей особенностью Песочницы является то, что Вам не нужно откуда-то качать или создавать этот образ. Он создастся на лету, из файлов вашей текущей ОС Windows.
Мы хотим всегда получить одно и то же «чистое» окружение для Песочницы. Но есть проблема: некоторые системные файлы могут меняться. Решением было создание «динамически генерируемого образа»: для изменённых файлов в него будут включаться их оригинальные версии, но вот неизменные файлы физически в этот образ входить не будут. Вместо них будут использоваться ссылки на реальные файлы на диске. Как показала практика — такими ссылками будут большинство файлов в образе. Лишь малая их часть (около 100 МБ) войдут в образ полностью — это и будет его размер. Более того, когда Вы не используете Песочницу, эти файлы хранятся в сжатом виде и занимают около 25 МБ. При запуске Песочницы они разворачиваются в тот самый «динамический образ» размером около 100 МБ.
Умное управление памятью
Управление памятью для Песочницы — ещё одно важное усовершенствование. Гипервизор позволяет запускать на одной физической машине несколько виртуальных и это, в общем, неплохо работает на серверах. Но, в отличии от серверов, ресурсы обычных пользовательских машин значительно более ограничены. Для достижения приемлемого уровня производительности Microsoft разработал специальный режим работы памяти, при котором основная ОС и Песочница могут с некоторых случаях использовать одни и те же страницы памяти.
В самом деле: поскольку основная ОС и Песочница запускают один и тот же образ ОС, то большинство системных файлах в них будут одни и те же, а значит нет смысла дважды загружать в память одинаковые библиотеки. Можно сделать это один раз в основной ОС, а когда тот же файл понадобится в памяти Песочнице — ей можно дать ссылку на ту же страницу. Конечно, требуются некоторые дополнительные меры для обеспечения безопасности подобного подхода, но Microsoft позаботилась об этом.
Интегрированный планировщик
В случае использования обычных виртуальных машин гипервизор контролирует работу виртуальных процессоров, работающих в них. Для Песочницы была разработана новая технология, которая называется «интегрированный планировщик», которая позволяет основной ОС решать когда и сколько ресурсов выделить Песочнице. Работает это так: виртуальный процессоры Песочницы работают как потоки внутри процесса Песочницы. В итоге они имеют те же «права», что и остальные потоки в вашей основной ОС. Если, к примеру, у вас работают какие-то высокоприоритетные потоки, то Песочница не будет отнимать у них много времени для выполнения своих задач, которые имеют нормальный приоритет. Это позволит пользоваться Песочницей, не замедляя работу критически важных приложений и сохраняя достаточную отзывчивость UI основной ОС, аналогично тому, как работает Linux KVM.
Главной задачей было сделать Песочницу с одной стороны просто обычным приложением, а с другой — дать гарантию её изоляции на уровне классических виртуальных машин.
Использование «снимков»
Как уже говорилось выше, Песочница использует гипервизор. Мы по сути запускаем одну копию Windows внутри другой. А это означает, что для её загрузки понадобится какое-то время. Мы можем тратить его при каждом запуске Песочницы, либо сделать это лишь раз, сохранив после загрузки всё состояние виртуальной ОС (изменившиеся файлы, память, регистры процессора) на диске. После этого мы сможем запускать Песочницу из данного снимка, экономя при этом время её старта.
Виртуализация графики
Аппаратная виртуализация графики — это ключ к плавному и быстрому пользовательскому интерфейсу, особенно для «тяжелых» в плане графики приложений. Однако, классические виртуальные машины изначально ограничены в возможностях напрямую использовать все ресурсы GPU. И здесь важную роль выполняют средства виртуализации графики, которые позволяют преодолеть данную проблему и в какой-то форме использовать аппаратную акселерацию в виртуальном окружении. Примером такой технологии может быть, например, Microsoft RemoteFX.
Кроме того, Microsoft активно работала с производителями графических систем и драйверов для того, чтобы интегрировать возможности виртуализации графики непосредственно в DirectX и WDDM (модель драйверов в ОС Windows).
В результате графика в Песочнице работает следующим образом:
Это позволяет виртуальному окружению получать полноценный доступ к аппаратно акселерируемой графике, что даёт как прирост производительности, так и экономию некоторых ресурсов (например, заряда батареи для ноутбуков) в следствие того, что для отрисовки графики больше не используются тяжелые расчёты на CPU.
Использование батареи
Песочница имеет доступ к информации о заряде батареи и может оптимизировать свою работу для его экономии.
Sandbox — выделенная среда для безопасного исполнения программ
Что такое Sandbox (песочница)
Это среда безопасного тестирования. Решение изолирует непроверенные изменения в коде и эксперименты от производственной среды и хранилища в контексте разработки программного обеспечения. Включая веб-разработку и контроль версий.
Песочница обнаруживает угрозы в файлах, передаваемых по сети (почтовые сообщения, загрузка файлов из Интернет и т. д.) с помощью продвинутых технологий поведенческого анализа. Система помогает обнаруживать и предотвращать APT-угрозы до их проникновения на конкретный хост. Далее мы разберем как работает система, как запускать «sandboxie», что позволяет делать песочница и какое решение выбрать.
Песочницы для бизнеса
Песочницы используются для запуска подозрительного кода из неизвестных вложений и URL-адресов и дальнейшего наблюдения за их поведением. Такая среда позволяет специалистам безопасно «взорвать» код, чтобы определить, как он работает и является ли он вредоносным. К контрольным признакам относятся:
Помимо тестов на безопасность, «песочницы» используют для запуска кода перед массовым развертыванием. В стандартной производственной бизнес-среде песочницы имеют решающее значение для нескольких сценариев разработки, кибербезопасности и исследований. Изолированная и безопасная среда необходима при исследовании кибербезопасности, ведь вредоносные программы активно сканируют корпоративные сети на открывшиеся уязвимости.
Песочница защитит:
Использование виртуальной среды песочницы позволяет организациям оценивать все аспекты сбора данных и проверять, что поток данных в обоих направлениях работает так, как должен. Само функционирование Sandbox зависит от того, что тестируется. Например, среда песочницы, используемая для тестирования вредоносного ПО, настроена и функционирует иначе, чем для тестирования кода и обновлений приложений. А песочница для исследования потенциальных вредоносных программ требует изоляции от производственного программного обеспечения.
В среде песочницы компании смогут:
API-песочница
Наличие песочницы API укрепит защиту любых приложений, использующих API. Программная архитектура полагается на API-интерфейсы как на ядро приложения. Тестировщики приложений должны проверять реакцию приложения на различные ответы API. Но если эти API-интерфейсы все еще находятся в разработке или разрабатываются третьей стороной, как вы можете полностью протестировать их? Именно здесь на помощь приходит песочница API.
Песочница API – это среда, которую тестировщики могут использовать для имитации характеристик производственной среды и создания смоделированных ответов от всех API, на которые опирается приложение. Решение снизит стоимость и риски, связанные с вызовом сторонних API во время тестирования.
Песочница API позволит:
Песочница для программистов
Я хочу сыграть с тобой в игру.
Но если быть точным, то я хочу презентовать вам результат моей работы за последние пару месяцев. Кодовое название — песочница.
Что это?
Суть данной системы проста: это песочница для программистов. Здесь можно и нужно писать исскуственный интеллект для своих ботов и играть с ботами других участников. Во что играть? Все просто — в дурака. Да-да, в карточную игру.
Данная система выросла из небольшого проекта по изучению пермишенов в Java. Изначально мне было просто интересно как работают разграничения выполняемого кода, как строится плагинная архитектура и т.д. Но в итоге захотелось обернуть все это в законченный продукт — вот как все вышло.
Кому интересно, давайте взглянем поближе на саму систему.
Прежде всего хочу сказать что все нижеизложенное вы можете найти на Intro странице в самой системе. Там же есть более-менее полное руководство, оно позволит преодолеть и без того низкий порог вхождения. Так же хочу заметить что стадия проекта — ОБТ, но это никоим образом не отражается на функциональности. Все запланированное для релиза уже на борту. Впереди лишь допиливание хотелок и полировка.
Как работает система?
Жизненный цикл игрока весьма прост. После регистрации и активации аккаунта* у Вас появляется доступ ко всем функциям системы. И теперь Вы, как игрок, можете писать, компилировать и загружать вашего бота.
После загрузки происходит раунд против самой системы. Это называется — квалификация. Цель лишь одна — проверить на вшивость код бота. Если бот играет не честно или играть не умеет, а может даже пытается мухлевать, он автоматом получает штраф и дальше играть не может. Для продолженния его нужно исправить и залить повторно.
Следом за квалификацией бот уже может участвовать в турнире. Игроки для турнира подбираются по Швейцарской системе. Игры проводятся каждый час. Турнир же длится неделю. Итоги подводятся каждое воскресенье. Очки распределяются по формуле рейтинга Эло. И первая тройка попадает в Историю Турниров. По всем победителям есть сводка — Зал Славы.
* тут прошу заметить что письма активации гугл может помечать как спам. Эту проблему, к сожалению, побороть не удалось. DNS настроил по полной, но все же, по непонятным мне причинам, доверие не на высоте.
Как пользоваться?
Интерфейс
Комментировать скрины я думаю будет лишним, поэтому постараюсь привлечь внимание картинками.
Как написать свою «песочницу»? Разбор простейшей «песочницы»
Предполагаемый уровень подготовки читателя
Разработка виртуальной машины – задача не для начинающих программистов, так что я предполагаю, вы имеете опыт в программировании для Windows, и, в частности:
• вы хорошо пишете на C/C++;
• имеете опыт в Win32 API программировании;
• прочли книги о внутреннем устройстве Windows (например, книги Марка Руссиновича);
• имеете базовое представление о сборке софта.
Вам также пригодится опыт разработки драйверов ядра Windows. Несмотря на то, что песочница требует некоторого количества кода, работающего в режиме ядра, при написании этого материала я учитывал, что вы можете не обладать нужными знаниями. Я раскрою тему разработки драйверов в деталях в рамках этого цикла статей.
Виртуальные машины и песочницы – в чём разница?
Виртуальные машины следовало бы разделить на два больших класса – «тяжелые» виртуальные машины, т.е. полностью эмулирующие железо, и легковесные виртуальные машины, которые эмулируют критически важные части операционной системы, такие как файловая система, реестр и некоторые другие примитивы ОС (например, мьютексы). Примеры легковесных виртуальных машин: Featherweight Virtual Machine, Sandboxie, Cybergenic Shade.
Featherweight Virtual Machine является проектом с открытым исходным кодом, однако есть некоторые недостатки, например, способ виртуализации вызовов функций ядра ОС. Featherweight Virtual Machine использует технологию «хуков», а это подразумевает под собой изменении кода ядра ОС – нечто ставшее запрещенным для 64-битных операционных систем, начиная с Vista. Подобного рода патчи кода ядра активируют Patch Guard —¬ специальный компонент ОС, вызывающий BSOD (синий «экран смерти») в таких случаях, поскольку Microsoft рассматривает патчи как злонамеренные действия. Поэтому FVM могла бы быть хорошей отправной точкой для первого взгляда на технологии виртуализации как таковые, но она недостаточно совместима с современными операционными системами. Основные трудности возникают при попытках сохранить совместимость с Patch Guard, мы детально рассмотрим эти проблемы позже.
Большая часть программистов изобретает технологии обхода Patch Guard, но подобные обходы ослабляют защиту ОС, делая её более уязвимой к «традиционным» зловредам уровня ядра, которые не могли бы быть запущены на ОС, защищенной Patch Guard. Нашей целью будет не обход или отключение Patch Guard, а сохранение совместимости с ним. Песочница должна добавить дополнительную защиту ОС, чтобы сделать её более устойчивой к атакам злоумышленников, а не ослаблять защиту, неправильно работая с Patch Guard.
В этом цикле статей мы собираемся сосредоточиться на разработке легковесной виртуальной машины. Главная идея состоит в том, чтобы перехватывать запросы ОС к критическим системным операциям и перенаправлять их к некоторого рода виртуальному хранилищу, к выделенной папке, для операций с файлами, в частности. Скажем, есть некоторое приложение, для которого мы хотим эмулировать модификации файла с именем C:\Myfile. Мы должны сделать копию этого файла в нашей виртуальной папке, скажем, C:\Sandbox\C\Myfile, и перенаправлять все операции, которые осуществляет приложение над данным файлом, к его виртуальному двойнику. То же самое касается операций над реестром и ещё некоторых системных механизмов.
Что следует виртуализировать и каким образом?
Давайте подведём итоги, что именно означает виртуализация операции. Начнём с виртуализации файловой системы. Как вы знаете, для получения доступа к файлу приложение сперва открывает его.
С точки зрения Windows, происходит вызов функции API, такой как CreateFile(). Если вызов осуществлен успешно, приложение может читать и писать в файл. Когда работа закончена, файл закрывается посредством вызова CloseHandle() API. Таким образом, мы должны иметь возможность перехватить вызов CreateFile(), изменить его параметры, такие как имя файла, которое приложение хочет открыть. Этим мы бы принудительно заставили приложение открыть другой файл.
Но перехватывать именно вызов CreateFile() – плохая идея по нескольким причинам: во-первых, приложение может открыть файл и другим образом, не только используя CreateFile(). Например, это может быть сделано посредством NtCreateFile(), нативного вызова API, которая по факту и вызывается в CreateFile(). Таким образом, перехватив NtCreateFile(), мы перехватим и CreateFile(), потому что в конечном итоге он вызывает NtCreateFile(). Но NtCreateFile() не является самой нижележащей функцией.
Так где же находится самая «нижняя» функция CreateFile(), которая будет вызываться, когда приложение хочет открыть/создать файл? Такая функция находится в коде режима ядра. Все файловые операции управляются драйверами файловых систем. Windows поддерживает так называемые фильтры файловых систем (в данной статье, мы сосредоточимся на подклассе таких фильтров — минифильтрах.), которые используются для фильтрации файловых операций. Следовательно, написав минифильтр файловой системы, мы смогли бы перехватывать все файловые системные операции, которые нам нужны. То есть наша первая цель – перехват системных вызовов файловых операций в режиме ярда путем написания драйвера минифильтра. Сделав это, мы бы смогли заставить ОС открывать абсолютно другой файл. В нашем случае, это будет виртуальный файл-двойник оригинала. Однако внимательный читатель может заметить: поскольку копирование – это весьма дорогая операция, то было бы неплохо немного оптимизировать процесс. Во-первых, можно проверить, был ли открыт файл только для чтения или нет. Если да, то нет нужды делать копию. Поскольку здесь не будет никаких изменений файла, мы можем просто предоставить доступ к исходному файлу.
Мы не будем перехватывать чтение или запись как таковые – вполне достаточно перехватывать функции режима ядра, эквивалентные (CreateFile() (OpenFile()) для того, чтобы перенаправлять всю остальную работу с файлами в нашу виртуальную папку. Однако виртуализации файловой системы недостаточно. Нам также следовало бы виртуализовать реестр и некоторые другие примитивы операционной системы. Но сейчас давайте сосредоточимся именно на виртуализации файловой системы, и начнем мы с обсуждения общих вопросов, касающихся устройства файловых систем и некоторых компонентов режима ядра.
Объекты привилегированного режима и объекты типа
Когда приложение открывает файл с помощью вызова интерфейса прикладного программирования, скажем, функцией CreateFile(), происходит много интересного: во-первых, для так называемых символических имен в заданном имени файла ищется их «родной» двойник, как показано ниже:
Например, если приложение открывает файл с названием «c:\mydocs\file.txt», его имя заменяется чем-то вроде «\Device\HarddiskVolume1\mydocs\file.txt». По сути, символическое имя «C:\» было заменено на «устройство» с именем «\Device\HarddiskVolume1». Во-вторых, в результате родное имя снова анализируется менеджером объектов — компонентом в привилегированном режиме операционной системы, чтобы определить, на какой драйвер поступал запрос на открытие. Когда драйвер регистрируется в системе, он представляется структурой DRIVER_OBJECT. Эта структура, наряду с другими вещами, содержит список устройств, за которые драйвер несет ответственность. Каждое устройство, в свою очередь, представляется структурой объекта устройства (DEVICE_OBJECT) и драйвер несет ответственность за создание объектов устройств (DEVICE_OBJECTs), которыми он собирается управлять.
Менеджер объектов проходит через один компонент за раз и пытается определить «итоговое» устройство, ответственное за данный компонент. В нашем случае, первым делом драйвер встречает компонент «\Device». В этот момент определяется объект типа для компонента. В данном случае, это каталог объектов (object directory). Я рекомендую вам скачать утилиту winobj от systinternals.com, чтобы увидеть родное дерево каталога объектов. Оно очень похоже на дерево каталогов файловой системы — содержит каталоги объектов и различные системные объекты, такие как порты ALPC, именованные каналы, события, в виде «файлов». Как только тип объекта определяется и так называемый «тип объекта» извлекается, выполняются дальнейшие действия.
А теперь я должен сказать пару слов о том, что такое «объект типа». Во время загрузки Windows регистрирует с помощью диспетчера объектов много типов объектов, таких как объект каталога, событие, мутант (также известный разработчикам пространства пользователя как «мьютекс»), устройства, драйверы и так далее. Поэтому когда драйвер создает, скажем, объект устройства – на самом деле, он создает объект типа «устройство». Объект типа «устройство», в свою очередь, является объектом типа «объект типа». Иногда для программиста проще понять вещи, когда они рассматриваются на языке программирования, а не на разговорном языке, так что давайте выразим это понятие в C++:
Когда пользователь создает событие (event), он просто создает экземпляр типа eventType. Как вы можете заметить, эти объекты типа «объект типа» содержат множество методов: open(), parse () и т.д. Они вызываются менеджером объектов во время синтаксического разбора имени объекта, чтобы определить, какой драйвер отвечает за то или иное конкретное устройство. В нашем случае, сначала он встречает компонент «\Device», который является просто объектом типа «каталог» (directory object). Так, будет вызван метод parse() объекта типа «каталог» (objectDirectoryType), которому будет передан остаток пути в качестве параметра:
Метод parse(), в свою очередь, определит, что HarddiskVolume1 является объектом типа «устройство». Драйвер, ответственный за это устройство, извлекается (в данном случае, это драйвер файловой системы, который работает с этим томом), и метод parse () объекта типа «устройство» (deviceType), в конечном счете, вызывается c «остатком» пути (например, «\mydocs\file1.txt»). Драйвер фильтра файловой системы, о котором мы будем писать в этой статье (если быть точным, экземпляр драйвера), ответственный за указанный том, увидит именно этот остаток пути в параметрах, передаваемых соответствующей процедуре обратного вызова. Драйверы файловой системы отвечают за обработку этого «остатка» пути, так что метод parse() должен сказать диспетчеру объектов, что весь путь распознан, а значит, дальнейшая обработка имени файла не требуется. На самом деле, эти члены типа «объект типа» не документированы, но важно иметь в виду их существование, чтобы понять, как ОС работает с типами объектов ядра.
Фильтры файловой системы
Написание драйвера фильтра является далеко не простой задачей и требует много шаблонного кода. Существует масса запросов, получаемых от различного рода драйверов файловой системы (и следовательно, фильтров). Вы должны написать обработчик (или, более конкретно, диспетчерскую процедуру (dispatch routine)) для каждого типа запроса, даже если вы не хотите делать специальную обработку того или иного отдельного запроса. Типичная диспетчерская процедура драйвера-фильтра выглядит так:
В этом примере драйвер-фильтр канала проверяет, принадлежит ли запрос устройству драйвера файловой системы канала (указатель на объект-устройство сохранен в g_LegacyPipeFilterDevice), и если да, то он передает запрос нижнему устройству, например, нижележащему фильтру, или на сам драйвер устройства. Иначе процедура просто успешно завершает запрос. Запросы ввода- вывода отправляются диспетчером ввода-вывода, о котором упоминалось выше, в форме запроса пакетов ввода-вывода или же просто пакетов IRP. Каждый IRP, наряду с большим количеством других материалов, содержит так называемые кадры стека. Чтобы упростить вещи, вы можете представлять их просто кадрами стека процедуры, которые распределяются между зарегистрированными фильтрами так, чтобы каждый фильтр имел свой собственный кадр стека.
Кадр содержит параметры процедуры, которые могут быть прочитаны или изменены. Эти параметры включают в себя входные данные для запроса, например, имя файла, который будет открыт при обработке запроса IRP_MJ_CREATE. Если мы хотим изменить некоторые значения для нижнего драйвера, мы должны вызвать IoGetNextIrpStackLocation (), чтобы получить кадр стека нижнего драйвера. Большинство драйверов просто вызывают IoSkipCurrentIrpStackLocation(): эта функция меняет указатель кадра стека внутри IRP так, что драйвер нижнего уровня получает тот же кадр, как и наш драйвер. С другой стороны, драйвер может вызвать IoCopyCurrentIrpStackLocationToNext() для копирования содержимого кадра стека в кадр нижележащего фильтра, но это более затратная процедура, и ее обычно используют, если драйвер хочет выполнить какую-то работу после обработки запроса ввода-вывода путем регистрации процедуры обратного вызова, которая называется процедурой завершения ввода-вывода.
Функция PassThrough(), приведенная выше, должна быть зарегистрирована драйвером фильтра для получения уведомления от диспетчера ввода-вывода всякий раз, когда приложения отправляют запросы, которые мы хотим перехватить. Фрагмент кода ниже показывает, как это обычно делается:
Приведенный выше код регистрирует устройство-фильтр для запросов, отправляемых к именованным каналам. Сначала он получает экземпляр класса DEVICE_OBJECT виртуального устройства, которое представляет каналы:
Далее он заполняет массив MajorFunction обработчиком PassThrough() по умолчанию. Этот массив представляет все типы запросов, которые диспетчер ввода-вывода может отправить на устройства, контролируемые драйвером. Если вы хотите проводить обработку некоторых запросов особым образом, вы регистрируете дополнительные обработчики для них, как показано в коде на примере обработчика CreateHandler. Последний шаг – прикрепить наш фильтр к стеку драйверов:
Вспомним, как наша диспетчерская процедура PassThrough() передаёт запрос вниз по стеку через процедуру CallDriver(), просто передавая IRP в качестве параметра, и указатель на нижнее устройство. Данный указатель – это устройство, к которому мы прикрепились. Когда API-функция вызывает устройство, в какой-то момент она использует его имя, например, \\Device\NamedPipe, при этом она не знает ни о каких фильтрах. Но как получилось, что наш фильтр получает запрос? «Магия» осуществляется функцией IoAttachDeviceToDeviceStackSafe() – она прикрепляет наше прозрачное устройство фильтра (deviceObject), которое было создано с помощью IoCreateDevice(), к нижнему устройству, в нашем случае, к тому, которое называется \\Device\NamedPipe. С этого момента все запросы, направляемые к именованным каналам, сначала проходят через наш фильтр. Обратите внимание, что CreateIoDevice() передает NULL в качестве имени устройства. В данном случае имя не требуется, поскольку это устройство-фильтр и, следовательно, не будет никаких запросов, направляемых непосредственно к фильтру, вместо этого они пойдут устройству, но вышележащий фильтр перехватит их первым.
С этого момента мы почти закончили наш минимальный драйвер-фильтр. Все, что нам нужно сделать – это закодировать процедуру DriverEntry(), которая просто вызывает RegisterLegacyFilter:
Минифильтры файловой системы
Как вы видели в предыдущем разделе, мы написали много кода только для записи ключевых обработчиков драйвера, которые ничего не делают. Они необходимы, просто чтобы написать минимальный работающий драйвер. Чтобы упростить вещи, на сцену выходит новый тип драйверов-фильтров – драйверы минифильтров. Это плагины к «устаревшему» драйверу-фильтру FltMgr, или диспетчеру фильтров. Драйвер FltMgr является «традиционным» драйвером-фильтром, который реализует большинство шаблонного кода и позволяет разработчику создавать «полезную нагрузку» к этому драйверу в виде плагина для него. Эти плагины называются минифильтрами файловой системы. Краткий макет минифильтров показан на рисунке ниже.
Заключение
В этой статье мы рассмотрели общие вопросы, касающиеся разработки драйверов-фильтров файловых систем, обсудили новый тип драйверов-фильтров – минифильтры, которые являются «плагинами» к «традиционным» драйверам-фильтрам. Мы коснулись вопросов синтаксического разбора имен устройств менеджером объектов, механизмов определения им драйвера, отвечающего за данное устройство и взаимодействия менеджера объектов с менеджером ввода-вывода.
В следующей статье мы рассмотрим проблему виртуализации файловой системы с практической стороны и приступим к реализации инструмента «песочница», который виртуализирует работу с файлами. Любая коммерческая «песочница», однако, виртуализирует не только операции с файловой системой, но и множество других механизмов системы, таких как системный реестр, удаленный вызов процедур, именованные каналы и т.д.




