Что такое виртуальный драйвер

Обновлено: 03.07.2024

В пятницу на Хабре было опубликовано видео о том, как работает виртуализация на смартфонах Android. Ее разработали и довели до стадии прототипа в Parallels Labs два студента кафедры МиИТ Академического университета Санкт-Петербурга в рамках своей магистерской работы. Мне посчастливилось узнать, что у технологии под капотом, а также спросить участников проекта, какие задачи они решали, как преодолевали возникающие трудности и к чему в результате пришли. Обзор запланирован в двух частях. В этом посте будет короткий обзор существующих решений для виртуализации на Android, понятные схемы архитектуры нашего решения, короткое видео того, как все работает. Во второй части будет больше конкретики. Речь пойдет о виртуализации телефонной части смартфонов, звуковой подсистемы и системы ввода.

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

Введение: зачем всё это нужно?

Концепция Bring Your Own Device (или BYOD), когда сотруднику разрешено работать с самым удобным для него «железом», — палка о двух концах. С одной стороны, юзеру удобно использовать на службе то, чем он привык пользоваться дома. Это теоретически повышает его производительность труда. С другой — BYOD добавляет головной боли системным администраторам и IT-директорам, которые вынуждены каким-то образом решать задачу защиты корпоративных приложений и данных, которые теперь крутятся на смартфоне. Один из основных подводных камней – пользовательское поведение. Часто юзеры игнорируют запрет на закачку и установку демо-версий стороннего ПО, хотя внутри таких приложений может прятаться вирус или «троянец».

Очевидный способ оградиться от такого рода угроз – создать для ненадежного ПО специальную «песочницу»; либо, наоборот, создать такую «песочницу» для корпоративного софта и бизнес-данных. Оба подхода должны быть реализованы деликатно, то есть без посягательств на частную (SMS, фотки с вечеринок и др.) информацию сотрудника. Такие «песочницы» встречаются сплошь и рядом в индустрии разработки и тестирования ПО и создаются с помощью виртуализации. Мы решили сделать нечто подобное, но – на смартфонах.

Ищем аналоги

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


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

VMware Horizon Mobile — полноценный гипервизор второго типа, виртуализирующий аппаратное обеспечение абстрактной машины. Под проект было создано ядро Linux с патчами Android, поверх которого запускается созданное VMware пользовательское окружение Android. Гипервизор работает на распространенных типах процессоров ARM, не имеющих расширений для аппаратной виртуализации, и является процессом в хостовой (основной) ОС — например, в родной для Android-девайса операционке. Очевидно, что в данном случае виртуализация всего аппаратного обеспечения требует достаточно много вычислительных ресурсов. Но, что еще важнее, запуск более чем одного гипервизора будет слишком быстро «высаживать» батарейку. Планшет, разряжающийся за полчаса, никому не нужен. К тому же подход VMware показался существенно сложнее в реализации, чем подход Cells.

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

Реализация сценариев BYOD и создание песочницы различна: в случае Cells и VMware политики настраиваются на уровне пользовательских окружений Android; при использовании же TrustDroid пользователю необходимо настраивать политики и домены вручную для каждого приложения. Это сложнее и муторнее для пользователя, потому что пользовательских окружений может быть несколько. У TrustDroid не все ОК с безопасностью. Предполагается, что стандартные системные приложения Android и ядро ОС никогда не скомпрометированы, но это может быть неверно, т.к. при получении прав суперпользователя их можно подменить.

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

EmbeddedXEN — проект по портированию XEN на платформу ARM. Проект, насколько мне известно, пока не вышел из стадии активной разработки, а посему не может рассматриваться как законченное решение. В настоящее время в проекте уже адаптированы версии ядра Linux HTC Desire HD для работы в качестве Dom0.

Контейнерная виртуализация – это выход

LXC — надстройка над инфраструктурой пространств имен ядра Linux. Он не покрывает все потребности, возникающие при создании полностью изолированных контейнеров. Например, LXC не предоставляет механизмов виртуализации sysfs и стандартных устройств, таких как виртуальный терминал. Технология OpenVZ предоставляет все необходимые возможности для создания полностью изолированных контейнеров и широко используется хостерами. Поэтому первым делом разработчики попробовали портировать ее на ядро Linux, используемое в Android.

  • текущая экспериментальная версия патча OpenVZ есть для ядра версии 2.6.32, но на смартфонах, на которых разрабатывалась и тестировалась технология, работают ядра версии 2.6.35;
  • при попытке наложить патч OpenVZ на одно из используемых ядер не удалось пропатчить 166 файлов из 1682; кроме того, патч модифицирует 34 файла, специфичных для архитектуры x86.

Портирование такого количества изменений на ядро 2.6.35 показалось нам чрезмерным. Но, отказавшись от OpenVZ, мы лишились готового решения по виртуализации sysfs: при создании нового виртуального окружения OpenVZ копирует дерево системных объектов (kobject) корневого пользовательского окружения, что потребовало от нас дополнительных усилий.

Итак, решено было использовать стандартные Linux-контейнеры LXC и всю инфраструктуру ядра, отвечающую за реализацию пространств имен (namespaces) и разграничение групп ресурсов.

На рисунке показана архитектура нашего решения.


  • Панель управления. Графический интерфейс к LXC; позволяет управлять контейнерами (запуск, остановка, переключение активного контейнера).
  • Cупервизор ядра, на рисунке — AndCont supervisor. Инициализирует виртуальное состояние драйверов, перехватывая момент запуска контейнера, реализует переключение между контейнерами.
  • Механизм межконтейнерного взаимодействия (ICC). Средство коммуникации между контейнерами на основе Netlink, обходящее проверки в прикладных сетевых протоколах и на основе разделяемой памяти.
  • Диспетчер ввода. Нужен для совместного использование устройств ввода Android, работающих параллельно.
  • Драйвер виртуального фреймбуфера. Обеспечивает возможность одновременного использования экрана устройства.
  • Драйвер GPU. Реализует возможность одновременного использования GPU всеми контейнерами.
  • Binder. Драйвер IPC, сделанный в рамках проекта Android Open Source Project (AOSP).
  • Alarm. Интерфейс к часам.
  • Прокси-сервер для механизма управления радиоинтерфейсами (Radio Interface Layer, RIL). Обеспечивает совместный доступ нескольких контейнеров Android к оборудованию доступа к мобильным сетям.
  • Прокси-клиент RIL. Принимает запросы к сервису телефонии от приложений в контейнере и передает их прокси-серверу RIL.
  • Прокси-клиент аудио. Получает контроль над звуковыми потоками контейнера и передает их прокси-серверу аудио.
  • Прокси-сервер аудио. Воспроизводит звуковые потоки контейнеров.
  • Вспомогательный контейнер. Предназначен для запуска системных демонов и библиотек Android, по разным причинам вынесенных из гостевых Android.
Механизм управления контейнерами
  • Заблокирован сброс флага CAP_SYS_BOOT, отвечающего за возможность перезагрузки системы, который используется виртульной java-машиной Dalvik при ее инициализации.
  • Опущены проверки открытых файловых дескрипторов, отличных от стандартных в lxc_start.
  • Исправлен дефект, приводящий к утечке файловых дескрипторов из демона adbd, который используется для доступа к смартфону через USB.
  • Добавлены нотификации супервизора уровня ядра о запуске нового контейнера перед запуском процесса init.
Binder

Драйвер ядра binder — это механизм IPC, разработанный в рамках проекта AOSP. Наличие оригинального, отличного от стандартного IPC до конца не ясно, однако детали реализации binder были одним из препятствий для запуска нескольких виртуальных окружений Android. Проблема состояла в следующем. В этом драйвере есть статические переменные, значения которых можно установить системным вызовом ioctl. Этот системный вызов делает программа servicemanager, запускаемая в процессе инициализации Android. Драйвер binder проверяет, инициализированы ли эти переменные и, если да, то возвращает ошибку, что приводит к завершению программы servicemanager, а поскольку эта программа необходима для работы Android – то и к прекращению инициализации Android.

Таким образом, потребовалось создавать экземпляры упомянутых выше переменных для каждого контейнера и обращаться к экземпляру виртуального состояния, принадлежащему контейнеру, в контексте которого был сделан системный вызов ioctl().

Виртуализация периферийных устройств

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

Android предполагает, что использует периферийные устройства монопольно. Драйверы этих устройств часто написаны исходя из предположения, что их использует только одна ОС. При запуске нескольких Android на одном устройстве в периферийных устройствах, их драйверах, программном стеке Android возникают критические ошибки.

Таким образом, для работы нескольких Android в контейнерах требуется обеспечить возможность одновременного использования периферийных устройств всеми операционками.

  • Физическое устройство подменяется на виртуальное, благодаря чему все запросы Android к физическому устройству направляются в виртуальное устройство.
  • Виртуальное устройство выполняет часть запросов Android на физическом устройстве, а часть виртуально, например, изменяя виртуальное состояние в соответствии со своей политикой.
  • Виртуальное устройство имеет тот же интерфейс и поведение, что и физическое.
  • Интерфейс должен быть максимально совместимым со всеми доступными версиями Android;
  • Интерфейс должен быть единственным и использоваться для всех задач доступа к устройству.

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

Дисплей

Необходимость в разделении доступа контейнеров к экрану очевидна. При запуске нескольких контейнеров каждый из них начинает отображать свой UI на экране. Естественно, если не договориться о том, какой контейнер обладает эксклюзивным правом использовать экран, то на экране получится смешение пикселей и элементов интерфейса. Чтобы такого не происходило, экран надо виртуализовать. Необходимо, чтобы физическое устройство было подменено на виртуальное.

Согласно Android Porting Guide, для доступа к экрану используется драйвер типа Linux Framebuffer, и для портирования необходимо реализовать данный драйвер. Linux framebuffer имеет простой интерфейс, состоящий из двух десятков функций, большинство из которых имеют реализацию по умолчанию. Драйвер используется из пространства пользователя.

Перепрограммирование MMU GPU

Кроме драйвера фреймбуфера к физическому экрану имеет доступ GPU. Чтобы неактивные ОС не отображали свой UI на экране, требуется подменить операцию отображения их кадров. Выяснилось, что в случае с подопытными Google Nexus S и Samsung Galaxy SII экраны смартфонов копируют кадр для отображения из RAM при помощи DMA. Драйвер фреймбуфера сообщает экрану адрес, по которому находится кадр, предназначенный для отображения (память экрана). Таким образом, операция отображения кадра на экране выглядит как операция записи кадра в RAM устройства по определенному адресу.

Чтобы подменить операцию записи в RAM, требуется установить кем она может выполняться. В случае с обработкой графики запись кадра могут выполнять GPU или CPU. Современные GPU и CPU имеют в своем составе MMU. Для того чтобы кадры неактивных Android не записывались в память экрана, достаточно подменить отображение адресов в MMU так, чтобы адреса неактивных Android, отображаемые в память экрана, фактически указывали на обычный буфер в RAM устройства. Назовем его теневым буфером.

Теневой фреймбуфер

Если выделить теневой буфер для каждого Android, то при переключении активной ОС достаточно скопировать кадр на экране в теневой буфер предыдущего активного Android. Чтобы отобразить Android, ставший активным, требуется скопировать содержимое его теневого буфера в память экрана. Но теневой буфер занимает от 2 до 4 Мб физической памяти. Имея возможность вызывать перерисовку кадра при переключении активного Android, можно избавиться от выделения теневого буфера для каждого Android, оставив единственный теневой буфер.

Такая возможность предоставляется механизмом fb_early_suspend. Теневой буфер теперь становится не местом хранения кадра Android, а местом куда все неактивные ОС пишут свою картинку. Кроме того благодаря наличию MMU можно сократить размер теневого буфера до одной страницы физической памяти, отобразив все 2−4 Мб адресов в единственную страницу.

Виртуальный драйвер Linux Framebuffer

Типичный сценарий использования драйвера Linux Framebuffer заключается в отображении памяти экрана в адресное пространство пользовательского процесса системным вызовом mmap() и вызовах стандартных и специальных IOCTL.

Стандартные IOCTL обрабатываются стандартным обработчиком IOCTL подсистемы Linux Framebuffer в ядре ОС. Специальные IOCTL имеют нестандартную семантику и могут быть обработаны только драйвером физического Linux Framebuffer. Так как физический Linux Framebuffer был подменен на виртуальный, то mmap() и IOCTL вызываются у драйвера виртуального Linux Framebuffer.

Все вызовы mmap() обрабатываются полностью в драйвере виртуального Linux Framebuffer без использования драйвера физического Linux Framebuffer, т.к. семантика этого системного вызова стандартна. Процессы активного Android при вызове mmap() получают доступ к памяти экрана. Процессы неактивных Android при вызове mmap() получают доступ к теневому буферу вместо памяти экрана. Для всех запущенных Android создается виртуальное состояние драйвера Linux Framebuffer. Для активного Android все вызовы в драйвер виртуального Linux Framebuffer немедленно перенаправляются в драйвер физического Linux Framebuffer, который изменяет состояние физического драйвера Linux Framebuffer. Для неактивных Android стандартные IOCTL'ы изменяют их виртуальные состояния Linux Framebuffer. Нестандартные IOCTL'ы для неактивных Android возвращают ошибку. На устройствах Google Nexus S и Samsung Galaxy SII этого было достаточно.

Промежуточные выводы

О том, как была реализована виртуализация звука, телефонии и ввода пользователя — в следующей статье.

Первая статья про драйверы была уж совсем вводной, и мне подумалось, что её нельзя не дополнить рассказом про то, как устроены драйверы более современных устройств.

Для начала введём определение bus master: устройство, способное быть не только ведомым, но и ведущим на шине компьютера. То есть — не только отвечать на транзакции ввода-вывода, инициированные процессором, но и самостоятельно их инициировать — по собственной инициативе «ходить» в память.

История таких устройств уходит корнями в понятие DMA: ещё во времена прародителя микропроцессоров, микропроцессора 8080 (КР5080ИК80), появилось понимание, что процессор хорошо бы разгрузить от рутинной операции перетаскивания байтиков между устройствами в-в и памятью.

Контроллер DMA (Direct Memory Access) был внешней по отношению к устройству ввода-вывода подсистемой, которую нужно было явно запрограммировать — установить тип операции (пишем в память, читаем из памяти, копируем память-память), адрес(а) памяти, и пр. Собственно, я совершенно несправедливо пишу об этом в прошедшем времени — всё это вполне существует и сейчас, например, в микроконтроллерах.

Уже в режиме DMA работа драйвера выглядит сущственно иначе — от драйвера требуется не выполнять ввод-вывод, а подготовить настройки для устройства, активировать его, дождаться прерывания по окончанию ввода-вывода, и проверить успешность операции. Всё сказанное в предыдущей статье верно и для DMA устройств, но в дополнение к сказанному, драйвер должен понимать схему взаимодействия устройства и DMA контроллера, а иногда и явно аллоцировать и настраивать контроллер: если в старых устройствах привязка порта ввода-вывода к контроллеру DMA делалась фиксированно, то сейчас во многих случаях возможен полный роутинг или выбор канала DMA из 2-4 вариантов.

Отдельно следует заметить, что сама инициация очередной транзакции ввода-вывода может быть автоматической (DMA лупит с максимально возможной скоростью), автоматической с настройкой темпа (чтобы не съесть всю пропускную способность шины) или по событию.

При этом событием в развитых системах может быть прерывание, просто изменение состояния ножки микроконтроллера, или же источником события может быть другое устройство. Например, таймер. Это позволяет сопрячь воедино ЦАП, DMA engine и таймер так, чтобы подача очередного байта в ЦАП происходила с заданной (таймером) частотой. Есть и другие варианты агрегирования устройств, например, включение одного канала DMA по окончании работы другого. Без привлечения внимания процессора.

Уместно также сказать, что DMA контроллеры иногда умеют явно сопрягать пару каналов, чтобы обеспечивать непрерывность потока данных по окончании работы одного канала запускается второй и генерируется прерывание, по которому процессор снова загружает работой первый канал — для того же ЦАП это может быть жизненно важно.

Вернёмся из мира контроллеров во «взрослые» машины. Большинство современных подсистем ввода-вывода уже не базируются на внешнем DMA, а имеют его аналог прямо внутри.

Это устройства с режимом «мастер шины», bus master.

Проще всего их представить именно как устройства, имеющие встроенный в себя, личный и оптимально устроенный контроллер DMA.

Обычно такие устройства управляются через дерево дескрипторов в памяти: у устройства есть специальный регистр, в который процессор помещает адрес структуры в памяти, которая содержит задание для контроллера. Или, чаще, массив или список структур с такими заданиями. Контроллер самостоятельно читает из памяти задания и выполняет их шаг за шагом. Задание, как правило, состоит из идентификатора операции, адреса в памяти, где брать данные и дополнительных параметров, необходимых для выполнения операции. Например: < запись на диск, адрес на диске, адрес буфера в памяти >. Так устроены современные контроллеры всего: диска, USB, сетевого интерфейса.

Кроме структуры дескрипторов для такого устройства требуются ещё инструменты для обмена событиями: процессор должен уметь сообщить, что изменил или дополнил дескрипторы, а устройство — что закончило ввод-вывод частично или полностью. Второе выполняется, естественно, через прерывания, а для первого часто применяется регистр (дверной звонок — doorbell), в который процессор «стучится», чтобы обратить внимание устройства на изменения.

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

Отдельно в этом ряду стоят virtio устройства. Появились они как следствие победного шествия гипервизоров по миру. Традиционно гипервизор предлагал гостевой ОС некоторый набор виртуальных устройств, которые копировали то или иное популярное физическое устройство. Известную сетевую карту или дисковый контроллер. Но эмулировать «железное» устройство тяжело, неудобно и муторно — зачастую, приходится поддерживать совершенно не нужные в виртуальном мире свойства, при этом для целей виртуализации структура реального железного устройства, обычно, неоптимальна.

Это и навело авторов на то, чтобы спроектировать заведомо виртуальные устройства, которые никогда не будут (never say never © 007) реализованы в железе и нужны исключительно для общения гипервизора и гостевой ОС. Они созданы так, чтобы для большого числа разнотипных устройств можно было реализовать общую единообразную инфраструктуру, как в ядре гостевой ОС, так и в гипервизоре.

По сути драйвер virtio — это транспорт пакетов с запросами и ответами между гостевой ОС и гипервизором. Содержание пакета специфично для типа драйвера и его режима. Например, для сетевой карты это адрес пакета ethernet, а для диска — scatter-gather дескриптор с указанием типа дисковой операции и адреса на диске.

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

Нетрудно видеть, что стандарт virtio описывает довольно типовой обобщённый драйвер bus master устройства: мы передаём «устройству» запрос с адресом в памяти и параметрами запроса ввода-вывода, остальное происходит асинхронно.

На фоне вышесказанного говорить про DPC уже не так актуально, но раз в комментариях возникла дискуссия — дам краткое описание.

В некоторых ОС (Фантом «срисовал» это с NT, откуда они срисовали — не знаю) существует штатная поддержка запуска кода внутри «лёгких» нитей — Deferred Procedure Call. Это позволяет понизить время нахождения драйвера в прерывании: хендлер прерывания лишь фиксирует событие и, как максимум, считывает из устройства статус — один регистр. Остальное делается в DPC, которая быстро активируется и доделывает начатое.

Откровенно сказать, смысла в этом не так уж много — проще запустить в драйвере его собственную нить высокоприоритетную и делать ввод-вывод из неё. Однако, могут быть варианты. Можно выделить DPC группу приоритетов и гарантировать им приоритет всегда более высокий, чем у нити. Можно обеспечить сверхбыстрый шедулинг и передавать таким нитям процессор прямо сразу на выходе именно из того прерывания, которое этот DPC запросило, снизив латентность.

Отдельно отметим, что из DPC можно многое из того, что в прерывании нельзя. Что именно — зависит от ОС. В Фантоме внутри DPC можно всё, в том числе и заснуть на месяц. Грех, но — можно. NT, ЕМНИП, всё же, как-то ограничивает права DPC (то есть, это не обычные нити), но деталей я не помню.


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

В чём суть, капитан?

В архитектуре x86 есть понятие «колец защиты» («Ring») – режимов работы процессора. Чем ниже номер текущего режима, тем больше возможностей доступно исполняемому коду. Самым ограниченным «кольцом» является «Ring 3», самым привилегированным – «Ring -2» (режим SMM). Исторически сложилось, что все пользовательские программы работают в режиме «Ring 3», а ядро ОС – в «Ring 0»:

Режимы работы x86 процессора

Режимы работы x86 процессора

В «Ring 3» программам запрещены потенциально опасные действия, такие как доступ к I/O портам и физической памяти. По логике разработчиков, настолько низкоуровневый доступ обычным программам не нужен. Доступ к этим возможностям имеют только операционная система и её компоненты (службы и драйверы). И всё бы ничего, но однажды я наткнулся на программу RW Everything:

RW Everything действительно читает и пишет практически всё

RW Everything действительно читает и пишет практически всё

Эта программа была буквально напичкана именно теми функциями, которые обычно запрещаются программам «Ring 3» - полный доступ к физической памяти, I/O портам, конфигурационному пространству PCI (и многое другое). Естественно, мне стало интересно, как это работает. И выяснилось, что RW Everything устанавливает в систему прокси-драйвер:

Смотрим последний установленный драйвер через OSR Driver Loader

Смотрим последний установленный драйвер через OSR Driver Loader

Прокси-драйвера

В итоге получается обходной манёвр – всё, что программе запрещено делать, разработчик вынес в драйвер, программа устанавливает драйвер в систему и уже через него программа делает, что хочет! Более того – выяснилось, что RW Everything далеко не единственная программа, которая так делает. Таких программ не просто много, они буквально повсюду. У меня возникло ощущение, что каждый уважающий себя производитель железа имеет подобный драйвер:

Софт для обновления BIOS (Asrock, Gigabyte, HP, Dell, AMI, Intel, Insyde…)

Софт для разгона и конфигурации железа (AMD, Intel, ASUS, ASRock, Gigabyte)

Софт для просмотра сведений о железе (CPU-Z, GPU-Z, AIDA64)

Софт для обновления PCI устройств (Nvidia, Asmedia)

Во многих из них практически та же самая модель поведения – драйвер получает команды по типу «считай-ка вот этот физический адрес», а основная логика – в пользовательском софте. Ниже в табличке я собрал некоторые прокси-драйвера и их возможности:

Результаты краткого анализа пары десятков драйверов. Могут быть ошибки!

Результаты краткого анализа пары десятков драйверов. Могут быть ошибки!

Mem – чтение / запись физической памяти

PCI – чтение / запись PCI Configuration Space

I/O – чтение / запись портов I/O

Alloc – аллокация и освобождение физической памяти

Map – прямая трансляция физического адреса в вирутальный

MSR – чтение / запись x86 MSR (Model Specific Register)

Жёлтым обозначены возможности, которых явно нет, но их можно использовать через другие (чтение или маппинг памяти). Мой фаворит из этого списка – AsrDrv101 от ASRock. Он устроен наиболее просто и обладает просто огромным списком возможностей, включая даже функцию поиска шаблона по физической памяти (!!)

Неполный перечень возможностей AsrDrv101

Чтение / запись RAM

Чтение / запись IO

Чтение / запись PCI Configuration Space

Чтение / запись MSR (Model-Specific Register)

Чтение / запись CR (Control Register)

Чтение TSC (Time Stamp Counter)

Чтение PMC (Performance Monitoring Counter)

Alloc / Free физической памяти

Поиск по физической памяти

Самое нехорошее в такой ситуации - если подобный драйвер остаётся запущенным на ПК пользователя, для обращения к нему не нужно даже прав администратора! То есть любая программа с правами пользователя сможет читать и писать физическую память - хоть пароли красть, хоть ядро пропатчить. Именно на это уже ругались другие исследователи. Представьте, что висящая в фоне софтина, красиво моргающая светодиодиками на матплате, открывает доступ ко всей вашей системе. Или вирусы намеренно ставят подобный драйвер, чтобы закрепиться в системе. Впрочем, любой мощный инструмент можно в нехороших целях использовать.

Через Python в дебри

Конечно же я захотел сделать свой небольшой "тулкит" для различных исследований и экспериментов на базе такого драйвера. Причём на Python, мне уж очень нравится, как просто выглядит реализация сложных вещей на этом языке.

Первым делом нужно установить драйвер в систему и запустить его. Делаем "как положено" и сначала кладём драйвер (нужной разрядности!) в System32:

Раньше в похожих ситуациях я извращался с папкой %WINDIR%\Sysnative, но почему-то на моей текущей системе такого алиаса не оказалось, хотя Python 32-битный. (по идее, на 64-битных системах обращения 32-битных программ к папке System32 перенаправляются в папку SysWOW64, и чтобы положить файлик именно в System32, нужно обращаться по имени Sysnative).

Затем регистрируем драйвер в системе и запускаем его:

А дальше запущенный драйвер создаёт виртуальный файл (кстати, та самая колонка "имя" в таблице с анализом дров), через запросы к которому и осуществляются дальнейшие действия:

И ещё одна полезная программа для ползания по системе, WinObj

И ещё одна полезная программа для ползания по системе, WinObj

Тоже ничего особенного, открываем файл и делаем ему IoCtl:

Вот здесь чутка подробнее. Я долго думал, как же обеспечить адекватную обработку ситуации, когда таких "скриптов" запущено несколько. Не останавливать драйвер при выходе нехорошо, в идеале нужно смотреть, не использует ли драйвер кто-то ещё и останавливать его только если наш скрипт "последний". Долгие упорные попытки получить количество открытых ссылок на виртуальный файл драйвера ни к чему не привели (я получал только количество ссылок в рамках своего процесса). Причём сама система точно умеет это делать - при остановке драйвера с открытым файлом, он остаётся висеть в "Pending Stop". Если у кого есть идеи - буду благодарен.

В конечном итоге я "подсмотрел", как это делают другие программы. Выяснилось, что большинство либо не заморачиваются, либо просто ищут запущенные процессы с тем же именем. Но одна из исследованных программ имела кардинально другой подход, который я себе и перенял. Вместо того, чтобы переживать по количеству ссылок на файл, просто на каждый запрос открываем и закрываем файл! А если файла нет, значит кто-то остановил драйвер и пытаемся его перезапустить:

А дальше просто реверсим драйвер и реализуем все нужные нам вызовы:

Легко и непринуждённо в пару команд читаем физическую память

Легко и непринуждённо в пару команд читаем физическую память

PCI Express Config Space

Немного отвлечёмся на один нюанс про PCIE Config Space. С этим адресным пространством не всё так просто - со времён шины PCI для доступа к её конфигурационному пространству используется метод с использованием I/O портов 0xCF8 / 0xCFC. Он применён и в нашем драйвере AsrDrv101:

Чтение и запись PCI Config Space

Чтение и запись PCI Config Space

Но через этот метод доступны только 0x100 байт конфигурационного пространства, в то время как в стандарте PCI Express размер Config Space у устройств может быть достигать 0x1000 байт! И полноценно вычитать их можно только обращением к PCI Extended Config Space, которая замаплена где-то в адресном пространстве, обычно чуть пониже BIOS:

Адресное пространство современного x86 компа, 0-4 ГБ

Адресное пространство современного x86 компа, 0-4 ГБ

На чипсетах Intel (ну, в их большинстве) указатель на эту область адресного пространства можно взять из конфига PCI устройства 0:0:0 по смещению 0x60, подробнее описано в даташитах:


У AMD я такого не нашёл (наверняка есть, плохо искал), но сам факт неуниверсальности пнул меня в сторону поиска другого решения. Погуглив стандарты, я обнаружил, что указатель на эту область передаётся системе через ACPI таблицу MCFG

А сами ACPI таблицы можно найти через запись RSDP, поискав её сигнатуру по адресам 0xE0000-0xFFFFF, а затем распарсив табличку RSDT. Отлично, здесь нам и пригодится функционал поиска по памяти. Получаем нечто такое:

На всякий случай оставляем вариант для чипсетов Intel

Всё, теперь осталось при необходимости заменить чтение PCI Express Config Space через драйвер на чтение через память. Теперь-то разгуляемся!

Читаем BIOS

В качестве примера применения нашего "тулкита", попробуем набросать скрипт чтения BIOS. Он должен быть "замаплен" где-то в конце 32-битного адресного пространства, потому что компьютер начинает его исполнение с адреса 0xFFFFFFF0. Обычно в ПК стоит флеш-память объёмом 4-16 МБ, поэтому будем "сканировать" адресное пространство с адреса 0xFF000000, как только найдём что-нибудь непустое, будем считать, что тут начался BIOS:

В результате получаем:

Вот так в 10 строчек мы считали BIOS

Вот так в 10 строчек мы считали BIOS

Но подождите-ка, получилось всего 6 мегабайт, а должно быть 4 или 8 что-то не сходится. А вот так, у чипсетов Intel в адресное пространство мапится не вся флешка BIOS, а только один её регион. И чтобы считать всё остальное, нужно уже использовать SPI интерфейс.

Не беда, лезем в даташит, выясняем, что SPI интерфейс висит на PCI Express:


И для его использования, нужно взаимодействовать с регистрами в BAR0 MMIO по алгоритму:

Задать адрес для чтения в BIOS_FADDR

Задать параметры команды в BIOS_HSFTS_CTL

Прочитать данные из BIOS_FDATA

Пилим новый скрипт для чтения через чипсет:

Исполняем и вуаля - в 20 строчек кода считаны все 8 МБ флешки BIOS! (нюанс - в зависимости от настроек, регион ME может быть недоступен для чтения).

Точно так же можно делать всё, что заблагорассудится - делать снифер USB пакетов, посылать произвольные ATA команды диску, повышать частоту процессора и переключать видеокарты. И это всё - с обычными правами администратора:

Немного помучившись, получаем ответ от SSD на команду идентификации

Немного помучившись, получаем ответ от SSD на команду идентификации

А если написать свой драйвер?

Некоторые из вас наверняка уже подумали - зачем так изворачиваться, реверсить чужие драйвера, если можно написать свой? И я о таком думал. Более того, есть Open-Source проект chipsec, в котором подобный драйвер уже разработан.

Зайдя на страницу с кодом драйвера, вы сразу наткнетесь на предупреждение:

В этом предупреждении как раз и описываются все опасности, о которых я рассказывал в начале статьи - инструмент мощный и опасный, следует использовать только в Windows режиме Test Mode, и ни в коем случае не подписывать. Да, без специальной подписи на обычной системе просто так запустить драйвер не получится. Поэтому в примере выше мы и использовали заранее подписанный драйвер от ASRock.

Если кто сильно захочет подписать собственный драйвер - понадобится регистрировать собственную компанию и платить Microsoft. Насколько я нагуглил, физическим лицам такое развлечение недоступно.

Точнее я так думал, до вот этой статьи, глаз зацепился за крайне интересный абзац:

У меня под рукой нет Windows DDK, так что я взял 64-битный vfd.sys , скомпилированный неким critical0, и попросил dartraiden подписать его «древне-китайским способом». Такой драйвер успешно загружается и работает, если vfdwin запущена с правами администратора

Драйвер из статьи действительно подписан, и действительно неким китайским ключом:

Как оказалось, сведения о подписи можно просто посмотреть в свойствах.. А я в HEX изучал

Как оказалось, сведения о подписи можно просто посмотреть в свойствах.. А я в HEX изучал

Немного поиска этого имени в гугле, и я натыкаюсь на вот эту ссылку, откуда узнаю, что:

есть давно утёкшие и отозванные ключи для подписи драйверов

если ими подписать драйвер - он прекрасно принимается системой

малварщики по всему миру используют это для создания вирусни

Основная загвоздка - заставить майкрософтский SignTool подписать драйвер истёкшим ключом, но для этого даже нашёлся проект на GitHub. Более того, я нашёл даже проект на GitHub для другой утилиты подписи драйверов от TrustAsia, с помощью которого можно подставить для подписи вообще любую дату.

Несколько минут мучений с гугл-переводчиком на телефоне, и мне удалось разобраться в этой утилите и подписать драйвер одним из утекших ключей (который довольно легко отыскался в китайском поисковике):

И в самом деле, китайская азбука

И в самом деле, китайская азбука

И точно так же, как и AsrDrv101, драйвер удалось без проблем запустить!

А вот и наш драйвер запустился

А вот и наш драйвер запустился

Из чего делаю вывод, что старая идея с написанием своего драйвера вполне себе годная. Как раз не хватает функции маппинга памяти. Но да ладно, оставлю как TODO.

Выводы?

Как видите, имея права администратора, можно делать с компьютером практически что угодно. Будьте внимательны - установка утилит от производителя вашего железа может обернуться дырой в системе. Ну а желающие поэкспериментировать со своим ПК - добро пожаловать на низкий уровень! Наработки выложил на GitHub. Осторожно, бездумное использование чревато BSODами.

В Windows есть фича "Изоляция ядра", которая включает I/O MMU, защищает от DMA атак и так далее (кстати об этом - в следующих сериях)


Так вот, при включении этой опции, некоторые драйвера (в том числе RW Everything и китайско-подписанный chipsec_hlpr) перестают запускаться:

VirtualDrive.exe это исполняемый файл, который является частью CyberLink Virtual Drive разработанный Cyberlink Corporation, Версия программного обеспечения для Windows: 8.0.0.2529 обычно 492096 в байтах, но у вас может отличаться версия.

Расширение .exe имени файла отображает исполняемый файл. В некоторых случаях исполняемые файлы могут повредить ваш компьютер. Пожалуйста, прочитайте следующее, чтобы решить для себя, является ли VirtualDrive.exe Файл на вашем компьютере - это вирус или вредоносная программа, которую вы должны удалить, или, если это действительно допустимый файл операционной системы Windows или надежное приложение.

VirtualDrive.exe вирус или вредоносное ПО?

VirtualDrive.exe безопасно, или это вирус или вредоносная программа?

Первое, что поможет вам определить, является ли тот или иной файл законным процессом Windows или вирусом, это местоположение самого исполняемого файла. Например, для VirtualDrive.exe его путь будет примерно таким: C: \ Program Files \ Cyberlink Corporation \ CyberLink Virtual Drive \ VirtualDrive.exe

Чтобы определить его путь, откройте диспетчер задач, перейдите в «Просмотр» -> «Выбрать столбцы» и выберите «Имя пути к изображению», чтобы добавить столбец местоположения в диспетчер задач. Если вы обнаружите здесь подозрительный каталог, возможно, стоит дополнительно изучить этот процесс.

Еще один инструмент, который иногда может помочь вам обнаружить плохие процессы, - это Microsoft Process Explorer. Запустите программу (не требует установки) и активируйте «Проверить легенды» в разделе «Параметры». Теперь перейдите в View -> Select Columns и добавьте «Verified Signer» в качестве одного из столбцов.

Если статус процесса «Проверенная подписывающая сторона» указан как «Невозможно проверить», вам следует взглянуть на процесс. Не все хорошие процессы Windows имеют метку проверенной подписи, но ни один из плохих.

Наиболее важные факты о VirtualDrive.exe:

  • Имя: VirtualDrive.exe
  • Программного обеспечения: CyberLink Virtual Drive
  • Издатель: Cyberlink Corporation
  • Ожидаемое местоположение: C: \ Program Files \ Cyberlink Corporation \ CyberLink Virtual Drive \ подпапке
  • Ожидаемый полный путь: C: \ Program Files \ Cyberlink Corporation \ CyberLink Virtual Drive \ VirtualDrive.exe
  • SHA1: 45D2DF775F6D5E7A216C396EBC7B26E430EC5BB9
  • SHA256:
  • MD5: 7f90189cae3ed0b89a97d82a1e5a5089
  • Известно, что до 492096 размер байт в большинстве Windows;

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

Найти его местоположение и сравнить размер и т. Д. С приведенными выше фактами

Кроме того, функциональность вируса может сама влиять на удаление VirtualDrive.exe. В этом случае вы должны включить Безопасный режим с поддержкой сети - безопасная среда, которая отключает большинство процессов и загружает только самые необходимые службы и драйверы. Когда вы можете запустить программу безопасности и полный анализ системы.

Могу ли я удалить или удалить VirtualDrive.exe?

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

Лучшая диагностика для этих подозрительных файлов - полный системный анализ с ASR Pro or это антивирус и средство для удаления вредоносных программ, Если файл классифицируется как вредоносный, эти приложения также удаляют VirtualDrive.exe и избавляются от связанных вредоносных программ.

Однако, если это не вирус, и вам нужно удалить VirtualDrive.exe, вы можете удалить CyberLink Virtual Drive с вашего компьютера, используя его деинсталлятор. Если вы не можете найти его деинсталлятор, вам может понадобиться удалить CyberLink Virtual Drive, чтобы полностью удалить VirtualDrive.exe. Вы можете использовать функцию «Установка и удаление программ» на панели управления Windows.

  • 1. в Меню Пуск (для Windows 8 щелкните правой кнопкой мыши в нижнем левом углу экрана), нажмите Панель управления, а затем под Программы:
    o Windows Vista / 7 / 8.1 / 10: нажмите Удаление программы.
    o Windows XP: нажмите Установка и удаление программ.
  • 2. Когда вы найдете программу CyberLink Virtual Driveщелкните по нему, а затем:
    o Windows Vista / 7 / 8.1 / 10: нажмите Удалить.
    o Windows XP: нажмите Удалить or Изменить / Удалить вкладка (справа от программы).
  • 3. Следуйте инструкциям по удалению CyberLink Virtual Drive.

Наиболее распространенные ошибки VirtualDrive.exe, которые могут возникнуть:


• «Ошибка приложения VirtualDrive.exe».
• «Ошибка VirtualDrive.exe».
• «VirtualDrive.exe столкнулся с проблемой и будет закрыт. Приносим извинения за неудобства».
• «VirtualDrive.exe не является допустимым приложением Win32».
• «VirtualDrive.exe не запущен».
• «VirtualDrive.exe не найден».
• «Не удается найти VirtualDrive.exe».
• «Ошибка запуска программы: VirtualDrive.exe».
• «Неверный путь к приложению: VirtualDrive.exe».

Аккуратный и опрятный компьютер - это один из лучших способов избежать проблем с VirtualDrive.exe. Это означает выполнение сканирования на наличие вредоносных программ, очистку жесткого диска cleanmgr и ПФС / SCANNOWудаление ненужных программ, мониторинг любых автозапускаемых программ (с помощью msconfig) и включение автоматических обновлений Windows. Не забывайте всегда делать регулярные резервные копии или хотя бы определять точки восстановления.

Если у вас возникла более серьезная проблема, постарайтесь запомнить последнее, что вы сделали, или последнее, что вы установили перед проблемой. Использовать resmon Команда для определения процессов, вызывающих вашу проблему. Даже в случае серьезных проблем вместо переустановки Windows вы должны попытаться восстановить вашу установку или, в случае Windows 8, выполнив команду DISM.exe / Online / Очистка-изображение / Восстановить здоровье, Это позволяет восстановить операционную систему без потери данных.

Чтобы помочь вам проанализировать процесс VirtualDrive.exe на вашем компьютере, вам могут пригодиться следующие программы: Менеджер задач безопасности отображает все запущенные задачи Windows, включая встроенные скрытые процессы, такие как мониторинг клавиатуры и браузера или записи автозапуска. Единый рейтинг риска безопасности указывает на вероятность того, что это шпионское ПО, вредоносное ПО или потенциальный троянский конь. Это антивирус обнаруживает и удаляет со своего жесткого диска шпионское и рекламное ПО, трояны, кейлоггеры, вредоносное ПО и трекеры.

Обновлено ноябрь 2021 г .:

Мы рекомендуем вам попробовать этот новый инструмент. Он исправляет множество компьютерных ошибок, а также защищает от таких вещей, как потеря файлов, вредоносное ПО, сбои оборудования и оптимизирует ваш компьютер для максимальной производительности. Это исправило наш компьютер быстрее, чем делать это вручную:

скачать


(опциональное предложение для Reimage - Cайт | Лицензионное соглашение | Политика конфиденциальности | Удалить)

Загрузите или переустановите VirtualDrive.exe

Как мне смонтировать виртуальный диск в CyberLink Power2Go 8?

Cyberlink Virtual Drive - это своего рода виртуальный диск в вашей системе или в сети, который использует ваша система. Если вы отключите это, вы больше не сможете получить доступ к виртуальному диску. Он также может быть связан с дисководом DVD / Blu-Ray, поэтому его отключение может вызвать проблемы.

Читайте также: