
Прямой доступ к диску для записи в Windows 7
При разработке программы для защиты флешек от вирусов возникла необходимость записи секторов напрямую на диск. Прямой доступ к диску осуществлялся через функцию CreateFile. Под Windows XP все работало нормально, а под Windows 7 при попытке записи сектора возвращалась ошибка Access Denied, при том, что при открытии диска на запись никаких ошибок не возникало. После длительных поисков причины было выяснено следующее: еще в самом начале разработки в Windows 7 была обнаружена критическая уязвимость. Если не вдаваться в нудные технические подробности, то смысл ее заключался в том, что злоумышленник мог открыть системный диск напрямую для записи и поместить любой злонамеренный код в файл подкачки. В Microsoft решили проблему с присущей им дубовой прямолинейностью - просто взяли и запретили прямую запись на диски. Но поскольку нельзя, но было очень нужно, то способ обхода защиты нашелся очень быстро. Оказывается, что запись на диски запрещена не полностью, система разрешает записывать данные в нулевую дорожку диска и в неразмеченные области. Такое поведение вполне объяснимо: надо же как-то форматировать диски штатными средствами без дополнительных танцев с бубнами. Значит для того, чтобы система разрешила запись в произвольное место диска, она сперва должна определить его как неразмеченный. А это достигается уничтожением нулевого сектора диска перед записью. Естественно, что перед уничтожением надо сохранить все данные из нулевого сектора в сухом прохладном месте, а потом вернуть их обратно.
Порядок действий следующий: открыть диск для чтения-записи, попробовать записать нужный сектор. Если произошла ошибка Access Denied, то надо прочитать нулевой сектор, записать вместо него нули, после этого обязательно закрыть диск. Это нужно, чтобы система при повторном обращении посчитала диск неразмеченным и разрешила запись в любой сектор. Затем снова открываем диск для чтения-записи. После записи нужных данных восстанавливаем нулевой сектор и закрываем диск. Все, наша задача выполнена, данные записаны, система спокойна. У этого способа есть и минусы. Так, если работа вашей программы по какой-то причине завершилась аварийно до момента, когда она восстановила нулевую дорожку, то данные на диске могут стать недоступны или вообще потеряться. Способ проверен и хорошо работает на съемных дисках с файловой системой FAT/FAT32, на стационарных жестких дисках и других файловых системах я его не проверял.
Вот фрагмент кода на Ассемблере, взятый из рабочего проекта. При необходимости его можно легко портировать на другие языки программирования.
; Открыть диск для чтения и записи
invoke CreateFile,drvName,GENERIC_READ+GENERIC_WRITE,\
FILE_SHARE_READ+FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL
; Сохранить хэндл
mov [hFile],eax
; Сразу прочитать нулевую дорожку
invoke ReadFile,[hFile],mbr,512,tmp,NULL
; Установить смещение на нужный сектор
invoke SetFilePointer,[hFile],512*numberofsector,0,FILE_BEGIN
; Попытаться записать нужный сектор
invoke WriteFile,[hFile],new_sector,512,tmp,NULL
or eax,eax
; Ошибок записи не произошло
jnz close_drive_and_exit
; Получить код последней ошибки
invoke GetLastError
; Ошибка Access Denied?
cmp eax,5
; Произошла какая-то другая критическая ошибка
jne close_drive_and_exit
; Уничтожить нулевую дорожку
invoke SetFilePointer,[hFile],0,0,FILE_BEGIN
invoke WriteFile,[hFile],zerobuff,512,tmp,NULL
; Закрыть диск
invoke CloseHandle,[hFile]
; Открыть заново диск с уничтоженной дорожкой
invoke CreateFile,drvName,GENERIC_READ+GENERIC_WRITE,\
FILE_SHARE_READ+FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL
; Сохранить хэндл
mov [hFile],eax
; Установить смещение на нужный сектор
invoke SetFilePointer,[hFile],512*numberofsector,0,FILE_BEGIN
; Записать нужный сектор
invoke WriteFile,[hFile],new_sector,512,tmp,NULL
; Записать нулевую дорожку обратно
invoke SetFilePointer,[hFile],0,0,FILE_BEGIN
invoke WriteFile,[hFile],mbr,512,tmp,NULL
close_drive_and_exit:
; Закрыть диск
invoke CloseHandle,[hFile]
Код приведен минимально необходимый, без дополнительной обработки возможных ошибок. В реальной ситуации, конечно, надо позаботиться о лучшей сохранности прочитанной нулевой дорожки, об обработке ситуации в случае ошибки записи данных на диск с уничтоженной нулевой дорожкой и т.д. Все это вы можете сделать самостоятельно.
Не зря говорится: "Что бы русский ни делал - все равно получается автомат Калашникова". Хотел как лучше, а в результате нашел способ как лишний раз наклонить защиту системы :)