waqur: (Евро)
[personal profile] waqur


Ребята из Майкрософт изрядно наложили в штаны, когда появился руткит, который захватывал контроль над машиной в режиме ядра через своп файл и прямой доступ к диску. Его написала 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 евро, между прочим.

Однако, неделя траханий, несомненно увлекательных экспериментов с доступом к диску в новой винде (а потом и вдумчивое чтение статей по CreateFile и FSCTL_LOCK_VOLUME в MSDN и KB 942448 - когда уже всё получилось, ну конечно же) показали, что способ есть. Никакой драйвер не нужен, и разговоры про "direct access ban for user-mode processes" - это просто басни для лохов, у которых есть лишних 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 сборку одной программы, которая реализует вышеуказанный алгоритм, не выявил никаких проблем.

Date: 2009-05-22 06:14 pm (UTC)
From: [identity profile] cd-riper.livejournal.com
т.е. диски нужно размонтировать чтобы получить доступ?

я не понимаю, а почему они не сделали проще -- для прямого доступа к диску нужны админские права. нормальное решение проблемы.

Date: 2009-05-22 06:58 pm (UTC)
From: [identity profile] waqur.livejournal.com
Да, нужно размонтировать и держать залоченными (иначе система их сразу смонтирует обратно).
К тому же, при работе с физическими дисками, надо держать залоченными и размонтированными все логические диски (разделы).

Date: 2009-05-25 03:40 pm (UTC)
From: [identity profile] japanspy.livejournal.com
Я бы завел отдельный тематический блог и туда дублировал эти посты. И аудитория будет целевая и КПД просветительства выше.

Date: 2009-05-25 03:46 pm (UTC)
From: [identity profile] waqur.livejournal.com
Да лениво как-то перелогиниваться каждый раз. К тому же, у меня ограниченный объём материала.

Date: 2009-05-25 03:48 pm (UTC)
From: [identity profile] waqur.livejournal.com
И просветительство идёт в основном через гугл ( например http://waqur.livejournal.com/264932.html?thread=926692 ) по ключевым словам, так что заинтересованные всё найдут.

Date: 2009-05-25 03:52 pm (UTC)
From: [identity profile] japanspy.livejournal.com
Согласен. Но смесь инженерии с художественной прозой как раз читалось бы как серия развлекательных статей (для гиков).

Насчет объемов - да. Ну его нафиг, профессиональное блоггерство.

Date: 2009-05-25 04:02 pm (UTC)
From: [identity profile] waqur.livejournal.com
Кстати,

http://waqur.livejournal.com/tag/it

и

http://waqur.livejournal.com/data/rss?tag=it


Из последнего даже можно соорудить транслируемый аккаунт (вроде [livejournal.com profile] news2_ru_rss) и, например, зафрендить.
Edited Date: 2009-05-25 04:04 pm (UTC)

Date: 2009-05-25 04:08 pm (UTC)
From: [identity profile] japanspy.livejournal.com
Можно, технически. Но целевой блог смотрится выигрышнее, что я изначально и хотел сказать.

Date: 2010-02-16 11:02 pm (UTC)
From: [identity profile] krokokot.livejournal.com
Спасибо за пост, подро..., помогло. :-)

Ма-аленькая поправочка: не "запретили прямой доступ к диску", а "запретили прямую запись на диск". Ибо CreateFile происходит вполне успешно, а вот WriteFile клеит ласты, если пишем дальше 16-го сектора.

В общем-то это вполне логично было-бы сделать уже давно. Ибо:
"На самом деле Microsoft выбрала правильное решение, исправив древний баг, на который до сих пор просто как-то не обращали внимания. Прямая запись на неразмонтированный том чревата полным разрушением последнего. Допустим, прикладная программа модифицирует запись MFT для восстановления ошибочно удаленного файла, а в это же самое время операционная система перемещает MFT на другое место или использует освободившуюся запись для размещения нового файла. В результате происходит хаос." Источник: http://www.insidepro.com/kk/270/270r.shtml

Обратный путь...

Date: 2010-11-10 03:50 pm (UTC)
From: [identity profile] yuriy-bolgov.livejournal.com
Спасибо за пост. Очень сэкономило время.

А вот такой вопрос: я через Setup API получил дескрипторы всех storage устройств с помощью SetupDiGetDeviceInterfaceDetail. Есть ли путь получить список всех разделов с помощью дескриптора устройства ?

Date: 2010-11-10 04:18 pm (UTC)
From: [identity profile] waqur.livejournal.com
В принципе, Setup API - это программный интерфейс к тому, что видно из виндового Device Manager'а, а из него во-первых мало чего видно по интересующей вас теме (например, не видны разделы, которые существуют, но не смонтированы из-за неподдерживаемого виндой типа файловой системы или смонтированы без присвоения буквы), а во-вторых, аггрегация объектов в нём ещё и отличается между Windows XP и Vista/7.

До 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).

Date: 2010-11-10 04:20 pm (UTC)
From: [identity profile] waqur.livejournal.com
Опечатка, вместо

"Кстати, физические диски, именуемые в Win32 \\.\PhysicalDriveX - это тоже ссылки вида PhysicalDriveX из \GLOBAL?? в \Device\HarddiskX\PartitionY."

должно быть

"Кстати, физические диски, именуемые в Win32 \\.\PhysicalDriveX - это тоже ссылки вида PhysicalDriveX из \GLOBAL?? в \Device\HarddiskX\DRZ."

Date: 2010-11-10 04:26 pm (UTC)
From: [identity profile] waqur.livejournal.com
Не забывайте также, что у тома может быть несколько точек монтирования -- например, Volume{FF199C10-ECE4-11DF-9621-9353DFD72085} может быть одновременно смонтирован как диск C: и как папка на диске D:, например D:\disk_c

Date: 2010-11-10 04:29 pm (UTC)
From: [identity profile] waqur.livejournal.com
А ещё имена вида Volume{FF199C10-ECE4-11DF-9621-9353DFD72085} хороши тем, что они не меняются, сколько раз бы юзер не выдергивал флешку и не вставлял обратно, сколько бы он не подключал других флешек перед ней, сколько бы не переименовывал буквы и точки монтирования в Computer Management / Disk Management в панели управления.

Date: 2010-11-10 05:13 pm (UTC)
From: [identity profile] yuriy-bolgov.livejournal.com
Немного друг друга не поняли :)

Имея HANDLE storage уст-ва можно ли например с помощью DeviceIoControl(..., IOCTL_DISK_GET_XXXX, ...) получить пути или дискрипторы к mounted volumes ?

Date: 2010-11-10 05:19 pm (UTC)
From: [identity profile] yuriy-bolgov.livejournal.com
Еще другими словами - есть ли путь спуска:

device ------> volume 1
|
-----> volume 2
|
-----> volume 3

В посте указывается как раз путь обратный volume -> disk number -> device

как то так... :)

Date: 2010-11-10 05:52 pm (UTC)
From: [identity profile] waqur.livejournal.com
HANDLE от storage устройства - это хэндл устройству с именем \\.\PhysicalDriveX = \Device\HarddiskX\DRZ или это хэндл к устройству с именем \Device\00000008, \Device\Ide\IdePort0 и т.д. ?

Date: 2010-11-10 05:57 pm (UTC)
From: [identity profile] yuriy-bolgov.livejournal.com
Это HANDLE к устройству полученый путем вызова CreateFile для пути вида: \\?\ide#diskwdc_wd3200bevt-22zct0___________________11.01a11#4&16492a87&0&0.0.0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}

путь получен из Setup API

Date: 2010-11-10 06:33 pm (UTC)
From: [identity profile] waqur.livejournal.com
А, понятно. Значит, второе.

Весьма нетривиальная задача.
Дело вот в чём. В ядре есть вложенные объекты:

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 иначе никак.

Date: 2010-11-10 06:46 pm (UTC)
From: [identity profile] waqur.livejournal.com
Ещё возможно IOCTL_STORAGE_GET_DEVICE_NUMBER не пробьёт динамические диски, созданные dmio.sys, виндовый softraid, но вы же понимаете почему - у них может быть более одного физического носителя и даже на разных шинах.

Date: 2010-11-10 06:52 pm (UTC)
From: [identity profile] yuriy-bolgov.livejournal.com
Спасибо за ответы! :)

Насколько надежно будет работать перебор NtCreateFile для "\Device\Harddisk" + N и для "\Device\Harddisk\Partition" + M ?

В обоих случаях перебираем до тех пор пока NTSTATUS == STATUS_SUCCESS

Date: 2010-11-10 07:22 pm (UTC)
From: [identity profile] waqur.livejournal.com
Я бы сделал NtOpenDirectoryObject/NtQueryDirectoryObject а потом отфильтровал полученные имена.

Date: 2010-11-10 07:31 pm (UTC)
From: [identity profile] waqur.livejournal.com
Или, чтобы не связываться с NativeAPI, можно сделать FindFirstVolume/FindNextVolume, получить список страшненьких Volume GUID'ов, прямо в таком виде их и открыть через CreateFile, и связать их с storage class устройствами через IOCTL_STORAGE_GET_DEVICE_NUMBER.

А далее уже заниматься украшательством - с помощью QueryDosDevice преобразовать Volume GUID имена в имена вида \Device\HarddiskVolumeN, с помощью той же функции получить список вообще всего, что есть, и всё, что имеет вид drive:[\path] и отображается в \Device\HarddiskVolumeN - тоже запомнить.

И уже затем показать ответ - если для данного Volume GUID есть точка монтирования, хотя бы одна - показать первую (или все), если нету - показать страшненький Volume GUID или Native path.

Кстати, Native Path можно отобразить в Win32 Path вот таким образом: \\?\GLOBALROOT\Device\HarddiskVolumeN.

Date: 2010-11-10 07:32 pm (UTC)
From: [identity profile] waqur.livejournal.com
команда mountvol.exe примерно так и делает

Date: 2010-11-11 08:50 am (UTC)
From: [identity profile] yuriy-bolgov.livejournal.com
Миша еще вопрос :)

Сделал нативный поиск через Nt(Open|Query)DirectoryObject. Похоже что для всех устройств Harddisk(N) сим. ссылка Partition0 - всегда ссылается на Harddisk(N)\DR(N) устройство ?

Date: 2010-11-11 08:58 am (UTC)
From: [identity profile] waqur.livejournal.com
да

только в Harddisk(N)\DR(M) N не всегда равно M

если флешку вынуть/вставить несколько раз, то M поменяется, а N - нет

M после загрузки Винды растёт строго инкрементально, и никогда не повторяется

N может переиспользоваться, если слот жёсткого диска освободился в результате отключения устройства

Date: 2010-11-11 10:04 pm (UTC)
From: [identity profile] yuriy-bolgov.livejournal.com
Таки доделал доступ... Каспер правда в шоке :) "Потенциально опасное ПО" :)

Date: 2013-12-18 10:02 am (UTC)
From: [identity profile] dominikanez.livejournal.com
Огромнейшее спасибо за подробности. Вы сэкономили мне гору времени!
Page generated 2026-05-07 11:23 am
Powered by Dreamwidth Studios