Наблюдательный программист может заметить, что разработчики Windows отказываются документировать самые вкусные и сочные места интерфейса данной ОС. И не напрасно — там скрыты поистине бесценные сокровища, от которых, к тому же, зависит безопасное
функционирование операционной системы.

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

 

Начнем-с…

Итак, что такое кэш Windows? Кэш или, правильнее, кэш файловой системы, представляет собой совершенно прозрачную для пользователя или программиста систему, которая находится где-то между файловой системой и виртуальной памятью ОС. Состоит он из набора функций ядра и системных потоков, которые вместе с диспетчером памяти обеспечивают кэширование данных для всех драйверов файловых систем Windows. В первую очередь кэш предназначен для увеличения производительности операционной системы за счет локального хранения (кэширования) тех данных, к которым часто обращаются пользовательские программы и подсистемы ядра ОС, а также, соответственно, для снижения количества обращений к жесткому диску. И ведь верно — стандартная процедура ввода-вывода, затрагивающая прямое обращение к жесткому диску — довольно трудоемкая операция, как с точки зрения скорости/времени, так и с точки зрения производительности. И тут дело даже не в скорости вращения дисков HDD или пропускной способности шины. В современных условиях, когда операционной системе приходится выполнять сотни операций в секунду, такой подход (прямое чтение/запись данных на жесткий диск без использования кэширования данных) выглядит малодействительным.

Наверное, я не согрешу против истины, заявив, что практически вся работа файловой системы так или иначе завязана на ее кэше. При этом работает он достаточно своеобразно: сначала полностью засоряется, после чего начинает освобождать для себя оперативную память, сбрасывая рабочие приложения в файл подкачки. Это сильно снижает скорость работы системы, особенно если на компьютере установлено менее 128 Мб ОЗУ (интересно, такие еще остались?). Мириться с этим можно, только если на твоей боевой машине не меньше гигабайта памяти. Если меньше, то проблема оказывает ся довольно серьезной. У диспетчера кэша есть одно необычное свойство — часть кэшируемых данных действительно находится в физической памяти.
Все дело в том, что диспетчер обращается к данным, проецируя их представления (mapping file) с помощью стандартных системных вызовов WinAPI.

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

Для общего сведения стоит отметить, что диспетчер кэша способен кэшировать не только файлы, но и потоки данных — последовательности байтов в файле.
Характерной особенностью кэша также является то, что у него нет собственного рабочего набора — он использует общий системный набор, в который входят кэш данных, пул подкачиваемой памяти и подкачиваемый код ядра и драйверов. Виртуальный размер кэша не отображается какими-либо счетчиками производительности, поэтому узнать его значение можно только через переменную ядра MmSizeOfSystemCacheInPages. Обычно его размер — 0x20000 страниц, что при странице, равной 4 Кб, будет составлять ровно 512 Мб. Для более точного отображения полного объема файловых данных, кэшируемых в системе, стандартный «Диспетчер задач» Windows показывает параметр «Системный кэш», отражающий суммарный размер системного рабочего набора и списков простаивающих и модифицированных страниц.

 

Лезем вглубь

Для отслеживания изменений в кэшируемых файлах диспетчер кэша использует специальную структуру — Virtual Address Control Block (VACB), которая описывае т каждый 256-килобайтный слот кэша. При загрузке системы диспетчер забирает часть неподкачиваемой памяти системы под свои нужды, то есть под размещение VACB. Адрес массива VACB сохраняется в переменной CcVacbs. При запросе на чтение данных из какого-либо файла диспетчер кэша должен ответить на два вопроса: находится ли файл в кэше, и какие VACB ссылаются на запрошенный адрес. Другими словами, диспетчер должен выяснить, проецируется ли представление файла на системный кэш. Для учета представлений данного файла диспетчер кэша поддерживает специальный массив указателей на VACB.Далее углубляться в структуру кэша не имеет смысла, она слишком сложна, и для ее описания просто не хватит ни места, ни времени.

Если интересно, отсылаю тебя к книге «Внутреннее устройство Windows» от признанных знатоков этой операционной системы М.Руссиновича и Д.Соломона.

Разработчику система предоставляет ряд переменных и функций, непосредственно связанных с системным кэшем. Самые интересные из них — это переменная MmSystemCacheStart, которая указывает на начальный виртуальный адрес кэша, и MmSystemCacheEnd, указывающая на его конечный адрес.

MmSystemCacheWs вернет нам суммарный размер системного рабочего набора. Вопрос лишь в том, как получить значение этих переменных. Их (как и кучу других не менее интересных переменных, от которых зависит работа системы) можно найти в структуре KDDEBUGGER_DATA32. Если лень искать в Сети, можешь покопаться на диске — там лежат сорцы драйвера, который реализует нужный тебе код и может показывать значения редких системных переменных. Основные функции работы с системным кэшем — CcCopyRead, CcCopyWrite и их более быстрые аналоги CcFastCopyRead и CcFastCopyWrite. Отличие этих функций в том, что CcFastCopyRead и CcFastCopyWrite ограничены использованием 32-разрядных смещений внутри файла и синхронного чтения/ записи.

Диспетчер кэша вызывается драйвером файловой системы с помощью указанных функций. К примеру, при операции чтения через вызов функций CcCopyRead (CcFastCopyRead) диспетчер создает представление файла в кэше для проецирования части запрошенного файла (file mapping) и считывает файловые данные в пользовательский буфер, копируя их из представления.

Поскольку драйверы файловых систем выполняются в ядре, они могут модифицировать данные, находящиеся в системном кэше, только с уведомления диспетчера кэша. Для этого предусмотрены такие функции как CcMapData, CcPinRead, CcPreparePinWrite и др., которые позволяют находить и модифицировать данные в виртуальной памяти без использования промежуточных буферов.
Существует три основных метода доступа к кэшируемым данным, каждый из которых рассчитан на применение в определенной ситуации: простое копирование, проецирование с фиксацией и прямое обращение к физической памяти.

 

Переходим к боевым действиям

Ну, мой дорогой друг, после того, как ты получил весомое представление о том, что такое системный кэш, возникает резонный вопрос: зачем все это нужно, и как все это можно использовать в свои целях?

Просто поразмысли сам — все данные, которыми процессы обмениваются друг с другом, так или иначе будут храниться в системном кэше. И если перехватывать напрямую системные функции для подмены чего-либо в адресном пространстве целевого процесса уже не кошерно, то манипуляции с данными процесса без перехвата системных функций заставят серьезно озадачиться производителей FIPS’ов, аверов и прочих «мегасупер-навороченных» (судя по рекламе) программ. И что же делать? Ну, первое, что приходит на ум — перехватить системные функции, которые используются диспетчером кэша.

Все они экспортируются ядром и начинаются с префикса Cc*, поэтому тебе не должно составить большого труда пропарсить таблицу экспорта и заменить обработчики на свои. Но это не есть гуд. Таблицы экспорта ядра, а также важнейших драйверов, скорее всего будут контролироваться аверами и проактивками, поэтому их модификация не принесет ничего хорошего.
Следовательно, перехват функций работы с кэшем будет не самым лучшим решением.

Мы пойдем другим путем — в структуре FILE_OBJECT, которая создается для каждой инстанции в системе, будь то файл, процесс или еще что-нибудь, есть указатели на очень интересные для нас вещи — это PRIVATE_CACHE_MAP и SHARED_CACHE_ MAP. PRIVATE_CACHE_MAP находится в самой структуре FILE_OBJECT по смещению 0x18. Далее нам нужно будет в FILE_OBJECT найти структуру SectionObjectPointer, которая, в свою очередь, по смещению 0x4 содержит указатель на структуру SHARED_CACHE_MAP.

 

Получаем файловый объект у исследуемого процесса

SectionObject = ( PSECTION_OBJECT)
FindProcessSectionObject ( pEprocess );
if (MmIsAddressValid(((PSEGMENT)SectionObject->
Segment)->ControlArea))
{
FileObject = ((PSEGMENT)SectionObject->Segment)->
ControlArea->FilePointer;
FileObject = (PFILE_OBJECT)
((ULONG)FileObject & 0xfffffff8);
}

PRIVATE_CACHE_MAP, как таковая, интереса для нас не представляет. Более интересной с точки зрения хака является структура SHARED_CACHE_MAP, потому что именно она по смещению 0x040 содержит указатель на массив VACBs, принадлежащий данному процессу. Получив доступ к VACB, ты фактически сможешь контролировать данные, принадлежащие процессу, и при необходимости изменять их. Кстати, если интересно, название файла в формате UNICODE_STRING, которому принадлежит FILE_OBJECT, ты сможешь найти по смещению 0x030. Главная цель, как ты понял из вышесказанного — найти указатель FILE_OBJECT, присущий тому или иному процессу или файлу; он содержит в себе все нужные данные.
Полный вариант кода ты, как всегда, сможешь найти на диске.

 

Заключение

В этой статье идет речь о не совсем простых вещах. Для освоения материала тебе понадобятся определенные знания и опыт программирования в ядре Windows, хотя, как мне кажется, в данной статье ничего сложного нет. Маленький совет — если хочешь досконально разобраться в работе файловой системы Windows и файлового кэша, обязательно прочитай книгу Раджива Нагара «Windows NT File System Internals». Несмотря на то, что книга 1997 года выпуска, своей актуальности она не потеряла до сих пор. Удачного компилирования, и да пребудет с тобой Сила!

 

Links

  • Для совершенствования своих навыков работы с файловым кэшем Windows советую посетить www.osronline.com.
  • Несмотря на то, что общее направление сайта — программирование в ядре, большая часть материалов посвящена разработке драйверов и филь тров файловых систем. К сожалению, на английском.

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии