Ребята из Майкрософт изрядно наложили в штаны, когда появился руткит, который захватывал контроль над машиной в режиме ядра через своп файл и прямой доступ к диску. Его написала 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 сборку одной программы, которая реализует вышеуказанный алгоритм, не выявил никаких проблем.
no subject
Date: 2009-05-22 06:14 pm (UTC)я не понимаю, а почему они не сделали проще -- для прямого доступа к диску нужны админские права. нормальное решение проблемы.
no subject
Date: 2009-05-22 06:58 pm (UTC)К тому же, при работе с физическими дисками, надо держать залоченными и размонтированными все логические диски (разделы).
no subject
Date: 2009-05-25 03:40 pm (UTC)no subject
Date: 2009-05-25 03:46 pm (UTC)no subject
Date: 2009-05-25 03:48 pm (UTC)no subject
Date: 2009-05-25 03:52 pm (UTC)Насчет объемов - да. Ну его нафиг, профессиональное блоггерство.
no subject
Date: 2009-05-25 04:02 pm (UTC)http://waqur.livejournal.com/tag/it
и
http://waqur.livejournal.com/data/rss?tag=it
Из последнего даже можно соорудить транслируемый аккаунт (вроде
no subject
Date: 2009-05-25 04:08 pm (UTC)no subject
Date: 2010-02-16 11:02 pm (UTC)подро..., помогло. :-)Ма-аленькая поправочка: не "запретили прямой доступ к диску", а "запретили прямую запись на диск". Ибо CreateFile происходит вполне успешно, а вот WriteFile клеит ласты, если пишем дальше 16-го сектора.
В общем-то это вполне логично было-бы сделать уже давно. Ибо:
"На самом деле Microsoft выбрала правильное решение, исправив древний баг, на который до сих пор просто как-то не обращали внимания. Прямая запись на неразмонтированный том чревата полным разрушением последнего. Допустим, прикладная программа модифицирует запись MFT для восстановления ошибочно удаленного файла, а в это же самое время операционная система перемещает MFT на другое место или использует освободившуюся запись для размещения нового файла. В результате происходит хаос." Источник: http://www.insidepro.com/kk/270/270r.shtml
Обратный путь...
Date: 2010-11-10 03:50 pm (UTC)А вот такой вопрос: я через Setup API получил дескрипторы всех storage устройств с помощью SetupDiGetDeviceInterfaceDetail. Есть ли путь получить список всех разделов с помощью дескриптора устройства ?
no subject
Date: 2010-11-10 04:18 pm (UTC)До storage устройств и разделов на них, как показывает практика, гораздо удобнее и переносимее можно добраться через Win32 API и Native API.
Скачайте WinObj и посмотрите на объекты
\Device\HarddiskX\PartitionY
\Device\HarddiskX\DRZ
где смысл цифр такой:
X - номер storage-устройства в системе, они могут повторяться если флешку вынуть-вставить по несколько раз
Y - номер раздела на нём
Z - неповторяющийся номер устройства
Эти все объекты - это ссылки на \Device\HarddiskVolumeK,
где K - какое-то левое число.
Диски, типа C:, D: - это тоже ссылки на \Device\HarddiskVolumeK
Они хранятся в \GLOBAL??.
Таким образом, вы можете сопоставить буковки дисков символьным путям вида
\Device\HarddiskX\PartitionY и узнать всё, что вам надо.
Некоторые разделы не имеют буковок, а всё же смонтированы.
До файлов на них можно добраться так:
\\.\Volume{FF199C10-ECE4-11DF-9621-9353DFD72085}\Windows\system32\notepad.exe
Для этого в \GLOBAL?? есть символьные ссылки вида Volume{FF199C10-ECE4-11DF-9621-9353DFD72085} на всё те же устройства \Device\HarddiskVolumeK
Кстати, физические диски, именуемые в Win32 \\.\PhysicalDriveX - это тоже ссылки вида PhysicalDriveX из \GLOBAL?? в \Device\HarddiskX\PartitionY.
Содержимое \GLOBAL?? лучше прощупывать не напрямую, а через QueryDosDevice, для лучшей совместимости с Terminal Services.
На всякий случай, если вы не знаете - WinObj использует для работы с Object Namespace функции
NtOpenDirectoryObject
NtQueryDirectoryObject
NtQuerySymbolicLinkObject
и другие связанные с ними (Native API).
no subject
Date: 2010-11-10 04:20 pm (UTC)"Кстати, физические диски, именуемые в Win32 \\.\PhysicalDriveX - это тоже ссылки вида PhysicalDriveX из \GLOBAL?? в \Device\HarddiskX\PartitionY."
должно быть
"Кстати, физические диски, именуемые в Win32 \\.\PhysicalDriveX - это тоже ссылки вида PhysicalDriveX из \GLOBAL?? в \Device\HarddiskX\DRZ."
no subject
Date: 2010-11-10 04:26 pm (UTC)no subject
Date: 2010-11-10 04:29 pm (UTC)no subject
Date: 2010-11-10 05:13 pm (UTC)Имея HANDLE storage уст-ва можно ли например с помощью DeviceIoControl(..., IOCTL_DISK_GET_XXXX, ...) получить пути или дискрипторы к mounted volumes ?
no subject
Date: 2010-11-10 05:19 pm (UTC)device ------> volume 1
|
-----> volume 2
|
-----> volume 3
В посте указывается как раз путь обратный volume -> disk number -> device
как то так... :)
no subject
Date: 2010-11-10 05:52 pm (UTC)no subject
Date: 2010-11-10 05:57 pm (UTC)путь получен из Setup API
no subject
Date: 2010-11-10 06:33 pm (UTC)Весьма нетривиальная задача.
Дело вот в чём. В ядре есть вложенные объекты:
1) storage class устройство, управляемое соответствующим драйвером минипорта (pciide.sys, usbstor.sys и т.д.), у него имя вроде \Device\Ide\IdePort0.
2) устройство блочного диска, у него имя вроде \Device\HarddiskN\DRM
3) отдельные устройства разделов с именами вроде \Device\HarddiskVolumeX
Два последних управляются стандартными виндовыми драйверами (ftdisk.sys, и ещё какой-то, не помню)
Вам надо связать (1) и (3).
Достаточно легко связать (2) и (3), как я описывал выше.
Во времена XP (1) и (3) можно было связать как-то с SetupAPI в обход (2), только метод не очень надёжный - например, если на физическом диске нет разделов или они не имеют букв, то он не работает.
http://www.ureader.com/message/881967.aspx
А в висте это сломали и всё обстоит чуть по-другому:
http://www.codeproject.com/kb/system/RemoveDriveByLetter.aspx
(они открывают все устройства (2)или(3), вызывают для них IOCTL_STORAGE_GET_DEVICE_NUMBER, затем открывают все устройства (1), вызывают тот же IOCTL, сверяют результаты, и так устанавливают соответствие).
Этот IOCTL-вызов проходит по стеку устройств аж до самого storage class driver без фильтрации, и таким образом устройства можно связать друг с другом. Довольно черезжопный метод, но из usermode иначе никак.
no subject
Date: 2010-11-10 06:46 pm (UTC)no subject
Date: 2010-11-10 06:52 pm (UTC)Насколько надежно будет работать перебор NtCreateFile для "\Device\Harddisk" + N и для "\Device\Harddisk\Partition" + M ?
В обоих случаях перебираем до тех пор пока NTSTATUS == STATUS_SUCCESS
no subject
Date: 2010-11-10 07:22 pm (UTC)no subject
Date: 2010-11-10 07:31 pm (UTC)А далее уже заниматься украшательством - с помощью QueryDosDevice преобразовать Volume GUID имена в имена вида \Device\HarddiskVolumeN, с помощью той же функции получить список вообще всего, что есть, и всё, что имеет вид drive:[\path] и отображается в \Device\HarddiskVolumeN - тоже запомнить.
И уже затем показать ответ - если для данного Volume GUID есть точка монтирования, хотя бы одна - показать первую (или все), если нету - показать страшненький Volume GUID или Native path.
Кстати, Native Path можно отобразить в Win32 Path вот таким образом: \\?\GLOBALROOT\Device\HarddiskVolumeN.
no subject
Date: 2010-11-10 07:32 pm (UTC)no subject
Date: 2010-11-11 08:50 am (UTC)Сделал нативный поиск через Nt(Open|Query)DirectoryObject. Похоже что для всех устройств Harddisk(N) сим. ссылка Partition0 - всегда ссылается на Harddisk(N)\DR(N) устройство ?
no subject
Date: 2010-11-11 08:58 am (UTC)только в Harddisk(N)\DR(M) N не всегда равно M
если флешку вынуть/вставить несколько раз, то M поменяется, а N - нет
M после загрузки Винды растёт строго инкрементально, и никогда не повторяется
N может переиспользоваться, если слот жёсткого диска освободился в результате отключения устройства
no subject
Date: 2010-11-11 10:04 pm (UTC)no subject
Date: 2013-12-18 10:02 am (UTC)