Ребята из Майкрософт изрядно наложили в штаны, когда появился руткит, который захватывал контроль над машиной в режиме ядра через своп файл и прямой доступ к диску. Его написала Joanna Rutkowska, и он работал по простой схеме:
1) заставить ядро вытеснить в своп заданную страницу памяти c кодом
2) за счёт прямого доступа к диску, заменить код в странице на требуемый
3) дождаться, пока внедрённый код получит управление в режиме ядра
Поскольку вся винда написана через то место, на котором сидят, и своппинг идёт не в отдельный раздел, а в регулярный файл, простым запретом прямого доступа к смонтированной своп-партиции тут проблему не решишь.
Корпоративная культура Майкрософта, предполагающая принятие всех решений "на бегу" в War Rooms исключает такой режим работы как "остановиться и немного подумать", поэтому, по сообщениям в интернете мелкомягкие просто тупо запретили прямой доступ к диску, начиная с Vista RC2.
Создав тем самым массу геморроя разработчикам всяких дисковых системных утилит - дефрагментаторов, восстанавливателей данных из повреждённых ФС, программ типа PartitionMagic, backup software, wipe software, undelete tools, unformat tools и так далее. Типа, всё, ребята, вылезай, приехали - http://support.microsoft.com/kb/942448/en-us - можно писать в бутсектор, неиспользуемую область, ещё в какую-то задницу, но не в область файловой системы. Можно в область файловой системы, но сначала размонтируйте раздел. А если нужен физический доступ не к разделу, а ко всему блочному устройству? С целью создания/удаления разделов, например? ERROR_ACCESS_DENIED, ага.
И если об оно было нормально описано в той же Knowledge Base статье, так было б ещё ничего. А то ж фактически информации нет. Статья из KB выглядит так, как будто её тоже писали в War Room'е, честное слово.
На этом фоне активизировались всякие хитрож*пые умники, которые начали предлагать дрова для прямого доступа к диску в обход всей этой кухни - http://www.eldos.com/rawdisk/ например. The sectors can be read or written from user-mode processes, thus going around direct access ban imposed by the operating systems. 500 евро, между прочим.
Однако, неделя
Также, не нужно делать и "жёсткое" размонтирование тома через DeleteVolumeMountPoint - это совершенно не помогает, к тому же это просто садизм над конченным юзером: после этой процедуры буквы дисков удалятся навсегда, это правило пропишется в реестре, и в случае краха вашей программы юзеру придётся возвращать буквы дисков к жизни через Панель Управления - Администрирование - Управление Компьютером - Управление Дисками или при помощи команды mountvol. Не поможет ни переподключение устройства, ни перезагрузка компьютера.
Не работают также и попытки вывести диск "в оффлайн" (типа, как вынутая дискета - буква есть, а читать нельзя) через IOCTL_VOLUME_OFFLINE и IOCTL_VOLUME_ONLINE.
Правильный способ открыть физический диск на запись под Вистой таков:
Шаг 1. Определяем список смонтированных разделов на этом физическом диске.
Как? Ну, можно получить список всех томов в системе через FindFirstVolume/FindNextVolume/FindVolumeClose, далее открыть каждый из них и через IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS или IOCTL_STORAGE_GET_DEVICE_NUMBER выяснить номер объемлющего физического диска, и сравнить с номером физического диска, который мы хотим открыть на запись.
Шаг 2. Размонтируем все найденные разделы, находящиеся на нашем физическом диске. Для этого их надо открыть на чтение-и-запись, с share mode, допускающим share read и share write, диспозиция - OPEN_EXISTING, и на каждом из них выполнить DeviceIoControl с кодами FSCTL_LOCK_VOLUME и FSCTL_DISMOUNT_VOLUME.
Программисты-параноики, которые боятся скрытых разделов, которые смонтированы без присвоения буквы (и помешают прямому доступу к диску, если их так оставить), могут сделать перечисление всех объектов вида \Device\HardDiskN\PartitionM в пространстве имён NT Object Manager'а, и поразмонтировать их через NtCreateFile/NtDeviceIoControl, не связываясь с DOSоподобными буквами и Win32 API.
Шаг 3. Наконец, открываем физический диск (CreateFile "\\.\PhysicalDriveN" или NtCreateFile "\Device\HardDiskN"). Режим - эксклюзивный (share mode = 0), права - чтение и запись, буферизация - выключена (FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH), диспозиция - OPEN_EXISTING. После открытия - опять FSCTL_LOCK_VOLUME и FSCTL_DISMOUNT_VOLUME (уже для всего физического диска в целом). Хендлы разделов диска не отпускаем, продолжаем удерживать их всех в заблокированном состоянии.
Шаг 4. Работаем с диском. Читаем, пишем, всё что угодно.
Шаг 5. FSCTL_UNLOCK_VOLUME и CloseHandle/NtClose для физического диска.
Шаг 6. FSCTL_UNLOCK_VOLUME и CloseHandle/NtClose для каждого из бывших логических дисков.
Шаг 7. Передёргиваем через Setup API storage driver физического диска, чтобы он в процессе переинициализации сообщил виндовому mount manager'у, о том, что у него новая таблица разделов. Это чтобы всем новым разделам были назначены новые Volume GUID'ы, а старые - "правильно" забыты.
Любые отклонения от этой процедуры приводят к катастрофическим последствиям. Это вам не XPшка, где можно всё делать в любом порядке. Закроете хендлы логических разделов раньше времени (сразу после открытия физического) - винда перемонтирует логические диски, включит защиту области FATа и каталогов - и посыпятся рандомом ошибки - то ERROR_ACCESS_DENIED, то WriteFile возвращает нулевую длину без кода ошибки, то WriteFile вообще не возвращает ошибок, но данные на диск не пишутся. Это всё гонки (race condition) с FASTFAT.SYS и NTFS.SYS.
А теперь, если внимательно и вдумчиво почитать KB 942448, то в хитросплетениях правил и ограничений, можно увидеть процедуру, которую я описал выше. Правда, здорово Майкрософт пишет мануалы?
UPD. Трёхчасовой стресс-тест, запускающий поочерёдно i386 и amd64 сборку одной программы, которая реализует вышеуказанный алгоритм, не выявил никаких проблем.