вторник, 26 октября 2010 г.

Виртуализация файлов изнутри

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

Итак, рассмотрим внутренности драйвера Luafv.sys.

Для начала глянем реестр:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\luafv\Instances]
"DefaultInstance"="luafv"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\luafv\Instances\luafv]
"Altitude"="135000"
"Flags"=dword:00000000

Судя по альтитуде, мы имеем дело с минифильтром.
Почему так? Все просто, фильтр менеджер может присоединять в стеке драйверов другие устройства(виртуальные), каждое такое устройство называется фрейм, и может содержать в себе несколько минифильтров.

Альтитуда нужна для их идентификации( есть определенные группы, для каждой из которых определен диапазонам альтитуд, к примеру FSFilter Anti-Virus, FSFilter Virtualization и т.д., подробнее в msdn).

В описании драйвера сказано, что это LUA File Virtualization Filter Driver, 
альтитуда равна 135000, что попадает в диапазон альтитуд FSFilter Virtualization(130000-139999).
На 99% можно быть уверенными что мы имеем дело с минифильтром, чтобы исключить оставшийся процент, достаточно заглянуть в импорт драйвера и увидеть:

.idata:000131A4 ;
.idata:000131A4 ; Imports from FLTMGR.SYS
.idata:000131A4 ;
.idata:000131A4 ; __declspec(dllimport) __stdcall FltCancelIo(x)
.idata:000131A4                 extrn __imp__FltCancelIo@4:dword


FLTMGR.SYS это фильтр менеджер, драйвер предоставляющий высокоуровневую среду для создания минифильтров и скрывающий низкоуровневую работу, с ним написание фильтров становится довольно простым делом.

Итак, Luafv.sys это минифильтр и это радует, т.к. искать колбеки будет довольно просто.

Пару слов о минифильтрах. Минифильтр позволяет повесить колбеки(pre и post) на определенные события. Минифильтр устанавливает требуемые ему колбеки в составе структуры, затем структура идет в ф-цию FltRegisterFilter.

После начала фильтрации(FltStartFiltering), при наступлении события(к примеру открытие/создание файла) будет вызываться колбек.
Итак, нас будет интересовать pre колбек устанавливаемый на событие IRP_MJ_CREATE.
После непродолжительного анализа кода выше ф-ции FltRegisterFilter находим структуру с перечисленными колбеками, символы нам наглядно и доступно показывают то, что мы ищем: LuafvPreCreate и LuafvPostCreate(этот нам не интересен).

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

FLT_PREOP_CALLBACK_STATUS FLTAPI LuafvPreCreate( __inout PFLT_CALLBACK_DATA data, __in PCFLT_RELATED_OBJECTS fltObjects, __deref_out_opt PVOID *completionContext )
{   
  • определяется, включена ли виртуализация ( переменная DisableVirt )
  • определяется юзер, который сделал запрос на создание файла(LuafvQueryVirtualizationCaller)
  • принимается решение о том, виртуализовать ли запрос на создание файла или нет, в частности проверятся расширение файла LuafvCheckExcludedName (файлы с расширениями перечисленными ниже не будут виртуализированы )
  • после того как решение принято, вызывается LuafvQueryStoreFile которая создает путь, куда будет перенаправлен новый файл: LuafvQueryStoreFile => LuafvFindUserStore => к примеру "user_name\AppData\Local\" + "\\VirtualStore\\" + имя файла   
  • вызывается LuafvReparse которая и выполняет перенаправление создаваемого файла в выбранный каталог, делается это стандартным способом, используя возможности минифильтра. Если бы данный драйвер не был минифильтром, для редиректа использовался бы скорее всего другой механизм - установка нового имени(вместе с путем) в FileObject + в установка в IRP IoStatus.Status равным STATUS_REPARSE + установка IoStatus.Information равным IO_REPARSE, в таком случае менеджер ввода-вывода инициировал бы повторную операцию открытия файла, послав IRP_CREATE, но уже с новым именем. Для минифильтра же вся работа по редиректу спрятана под высокоуровневой оболочкой, редирект выполняется попроще, см. ниже ф-цию LuafvReparse
}

NTSTATUS LuafvReparse( SOME_STRUCT *p, ... )
{
    //
    // файловый объект приходит в ф-цию через аргумент(в составе структуры) обычно в колбек приходит параметр
    // PCFLT_RELATED_OBJECTS fltObjects, в котором содержится файловый объект, но в данном случае до вызова
    // LuafvReparse данные рассовываются в собственные структуры
    PFILE_OBJECT fileObject = p->FileObject;

    fileObject->MaximumLength = newLength;   // устанавливается новая длина
    fileObject->Buffer = newBuffer;  // устанавливается буфер с новым именем файла ( включая путь )

    FltSetCallbackDataDirty();   // фильтр-менеджеру сообщается, что данные в колбеке изменились
}

Список расширений файлов, которые не будут виртуализированы:

"acm", "asa", "asp", "aspx", "x", "bat", "cer", "chm", "clb", "cmd", "cnt", "cnv", "com", "cpl", "cpx", "crt", "dll", "drv", "exe", "fon", "grp", "hlp", "hta", "ime", "inf", "ins", "isp", "its", "js", "se", "nk", "sc", "si", "sp", "st", "ui", "ls", "cx", "al", "cd", if", eg", "cf", "cr", "ct", "hb", "hs", "ys", "lb", "sp", "rl", "b", "vbe", "vbs", "vsmacros", "s", "wsc", "wsf", "wsh"

Таким не хитрым образом работает виртуализация для файлов в windows vista.

Комментариев нет:

Отправить комментарий