Драйвер-фильтр сокрытия файлов в файловой системе NTFS
Драйвер-фильтр сокрытия файлов в файловой системе NTFS
1 Кафедра «Программное обеспечение ЭВМ и информационные технологии» Курсовой проект по системному программированию Расчетно-пояснительная записка Тема: «Драйвер-фильтр сокрытия файлов в файловой системе NTFS» Москва, 2009 год Оглавление Введение 1. Аналитический раздел 1.1 Постановка задачи 1.2 Подсистема ввода-вывода 1.3 Драйверы режима ядра и средства их разработки 1.4 WDM драйверы и многослойная драйверная архитектура 1.5 Механизмы взаимодействия драйвера режима ядра и пользовательского приложения 2. Конструкторский раздел 2.1 Структура разрабатываемого программного продукта 2.2 Анализ и выбор алгоритма сокрытия данных 2.3 Описание функций драйвера 2.4 Описание функций пользовательского приложения 2.5 Взаимодействие драйвера и приложения3. Технологический раздел 3.1 Выбор языка и среды программирования 3.2 Пользовательский интерфейс 3.3 Тестирование драйвера Выводы Список используемой литературы Введение Задача надежной защиты информации от несанкционированного доступа является одной из древнейших и не решенных до настоящего времени проблем. Данная проблема актуальна как для пользователей ПК, которые хотят спрятать свои личные документы, программы и прочие данные, так и в ходе разработки специфического программного обеспечения, когда, к примеру, необходимо запускать исполняемый файл, скрытый от пользователя компьютера. Скрытие файлов в операционной системе Windows основано на перехвате обращений к файлам, что может осуществляться только резидентной программой. Сегодня распространено два подхода к решению данной задачи. Первый реализует программа Hide Folders XP: скрытие папок осуществляется с помощью специального драйвера, перехватывающего обращения к файловой системе. В программе доступно 3 режима защиты файлов и папок: скрывание, блокирование доступа и комбинированный режим (скрывание и блокирование доступа). Одним из недостатков подобных программ является возможность обойти защиту. Зачастую достаточно бывает перезагрузить систему в безопасный режим. Примером второго подхода, который позволяет решить эту проблему, может служить TrueCrypt. На жёстком диске программа создаёт файл-контейнер, всё содержимое которого зашифровано одним из выбранных криптографических алгоритмов. Данный курсовой проект посвящен изучению первого подхода к проблеме скрытия файлов и папок, так как в рамках курса системного программирования перед нами не стоит задача использования алгоритмов шифрования для защиты информации. 1. Аналитический раздел 1.1 Постановка задачи Основной целью проекта является разработка комплекса программных средств, осуществляющего скрытие файлов на компьютерах IBM PC, работающих под управлением операционной системы Windows XP. Программный продукт должен обеспечивать удобный интерфейс для выбора скрываемого файла, и хранить в системе имена уже скрытых файлов и директорий. Выходными данными должна быть информация об успешном выполнении операции скрытия или описание произошедшей ошибки. 1.2 Подсистема ввода-вывода Для реализации поставленной задачи необходимо отслеживать обращение к дискам. Существует несколько подходов к решению этой задачи. Один из подходов - это установление ловушек перехвата сообщений прежде чем они достигнут пользователя. Эта методика очень проста и эффективна, но имеет ряд недостатков, наиболее важный из которых - необходимость прав администратора для работы. Вторая методика - это написание драйвера-фильтра файловой системы, который будет перехватывать запрос обращения к директории и принимать действия в зависимости от внутренних данных и ассоциированных с файлом правил. Работа с периферийными устройствами в ОС Windows возложена на подсистему ввода-вывода, которая состоит из служб режима пользователя и режима ядра, причем работа непосредственно с устройствами ведется в режиме ядра. Приложения взаимодействуют с подсистемой ввода-вывода с помощью специальных системных вызовов, которые передают управления коду подсистемы ввода-вывода с учетом всех требований безопасности, и являются частью API исполнительной среды, например Win32. Рис. 1. Схема обращения приложения к внешнему устройству В результате системного вызова связанного с вводом-выводом в подсистеме ввода вывода создается пакет запроса ввода-вывода (IRP - Input/output Request Packet), хранящий информацию об операции, которую необходимо выполнить с устройством: чтение, запись или управление. Также IRP могут создаваться в результате обработки другого запроса одной из компонент подсистемы ввода-вывода. По завершении обработки IRP уничтожаются. Центральное место в подсистеме ввода вывода занимает менеджер ввода-вывода, - специальная служба режима ядра, которая отвечает за координацию взаимодействия приложений и внешних устройств. В менеджер ввода-вывода передаются запросы из пользовательского режима. Он также координирует работу драйверов, работающих с конкретными типами устройств, которым он перенаправляет запросы ввода-вывода. Нижележащим звеном в цепи, связывающей приложение с периферийным устройством, являются драйверы устройств режима ядра, - загружаемые модули режима ядра (как правило, это файл с расширением .sys), образующие интерфейс между диспетчером ввода-вывода и соответствующим оборудованием. Драйверы, как правило, поставляются с оборудованием, их набор в ОС не является постоянным. Хотя в состав операционной системы включены драйверы к наиболее распространенным устройствам, для обеспечения дополнительной функциональности зачастую необходимо разработать собственные драйверы. 1.3 Драйверы режима ядра и средства их разработки Драйверы режима ядра могут быть классифицированы по различным признакам. По типу обслуживаемых устройств: 1. Драйверы аппаратных устройств 2. Драйверы файловой системы 3. Драйверы фильтры файловой системы 4. Сетевые редиректоры и серверы 5. Драйверы протоколов 6. Драйверы потоковых фильтров ядра. Поскольку в современных компьютерах периферийные устройства подключены через иерархическую систему шин, а действия, производимые с ними, многочисленны и сложны, за обслуживание одного устройства, как правило, отвечает несколько драйверов взаимодействующих через менеджер ввода-вывода, выстроенных в иерархическую цепочку называемую стеком драйверов. С этой точки зрения драйверы можно разделить на: 1. Монолитные драйверы - драйверы, которые не участвуют ни в одном стеке устройств, получая и завершая обработку всех поступающих IRP пакетов, самостоятельно обращаясь к своему обслуживаемому устройству. 2. Унаследованные (Legacy) драйверы - драйверы этого типа могут быть объединены в стек, но они не поддерживают PnP функции, могут использовать недокументированные функции WinNT 5, из-за чего не всегда переносимы на Win98. 3. WDM драйверы - драйверы написанные в соответствии со спецификацией WDM (Windows Driver Model), введенной в Windows 2000, поддерживающей Plug and play (динамическая идентификация устройств и энергосберегающие технологии) С точки зрения WDM, существует три типа драйверов: 1. Драйвер шины (bus driver), обслуживающий контроллер шины, адаптер, мост или любые другие устройства, имеющие дочерние устройства. 2. Функциональный драйвер (functional driver) - основной драйвер устройства, предоставляющий его функциональный интерфейс. 3. Драйвер фильтр (filter driver) - драйвер, предназначенный для расширения возможностей функционального драйвера. 1.4 WDM драйверы и многослойная драйверная архитектура Рассмотрим подробнее, как устроен стек драйверов в WDM. Каждый драйвер в стеке изолирует аппаратно зависимые возможности от вышестоящего уровня. На рисунке показаны типы драйверов, которые могут обслуживать устройство. В действительности, некоторые из этих типов могут отсутствовать в стеке. Рис. 2. Многослойная архитектура драйверов Над стеком находятся приложения. Они обрабатывают запросы пользователя или других приложений и вызывают или подсистему Win 32 или клиент драйвер пользовательского режима. 1. Драйвер аппаратной шины находится в самом низу стека. Microsoft предоставляет эти драйвера для всех шин, как часть операционной системы 2. Фильтр-драйвер аппаратной шины обычно добавляет новые функциональные возможности и поставляется Microsoft или системным интегратором. Для одной аппаратной шины может существовать неограниченное число фильтр-драйверов аппаратной шины. 3. Фильтр-драйверы нижнего уровня обычно изменяют поведение устройства или класса устройств. 4. Функциональный драйвер (functional driver) - основной драйвер устройства, предоставляющий его функциональный интерфейс. 5. Фильтр-драйверы верхнего уровня выполняют дополнительные манипуляции над IRP, к которому они подключены. Их количество для одного классового драйвера не ограниченно, при этом они являются для него прозрачными, т.е. классовый драйвер не подозревает о существовании фильтров. Рис. 3. Место драйверов в операционной системе Обычно, разбиение на основные и фильтр-драйверы делает разработчик основного драйвера. Но иногда фильтры разрабатываются сторонними разработчиками с целью расширить исходную функциональность устройства. При этом необходимо соблюдать осторожность, чтобы не помешать работе классового драйвера и поставляемых с ним фильтров. 1.5 Механизмы взаимодействия драйвера режима ядра и пользовательского приложения Необходимо выбрать механизм для передачи команд от приложения пользовательского уровня к драйверу режима ядра и для передачи информации, собранной фильтр-драйвером режима ядра на пользовательский уровень в приложение, которое будет отображать данные в удобной для пользователя форме. В операционных системах Windows были обнаружены следующие средства решения данной задачи: 1. WMI - расширение WDM предоставляющие интерфейс через который драйверы могут взаимодействовать с приложениями. С точки зрения приложения WMI реализован как COM-интерфейс. Драйвер же реализует функции WMI через специальные точки входа, стандартизированные в расширениях WDM. С помощью WMI можно осуществлять мониторинг и управление устройствами компьютера с другой машины по сети. 2. Системные вызов API Win32 - кроме WMI точек входа, драйверы WDM поддерживают точку входа c кодом функции IRP_MJ_DEVICE_CONTROL, которая отвечает за программное управление устройством с локального компьютера. С точки зрения приложения обращение к этой функции выглядит как вызов API-функции DeviceIOControl. Поскольку использование API вызова является более простым и быстрым в реализации подходом, чем доступ к информации через интерфейсы WMI, таким образом, значительно упрощая разработку приложения и драйвера, был выбран этот подход. 2. Технологическая часть 2.1 Структура разрабатываемого программного продукта Необходимые для работы компоненты 1. Пользовательское приложение, обеспечивающее выбор файла для сокрытия, Отображение уже скрытых файлов, загрузка и выгрузка драйвера 2. Драйвер-фильтр, обеспечивающий сокрытие файлов по разработанному алгоритму Рис.6. Схема взаимодействия драйвера и приложения Две компоненты системы взаимодействуют друг с другом через интерфейсы Win32 API. Приложение создает IRP с кодом IRP_MJ_DEVICE_CONTROL вызовом API-функции DeviceIoContol. Получив этот пакет, драйвер возвращает информацию о запросах, записывая ее в буфер, указанный приложением. Буфер представляет собой неструктурированный массив байтов, поэтому отдельным вопросом является упаковка и распаковка данных в соответствующие структуры. 2.2 Анализ и выбор алгоритма сокрытия данных Для скрытия файлов на диске нам нужно перехватить функцию ZwQueryDirectoryFile из ntdll.dll. Она является базовой для всех API перечисления файлов. API функции представляют и себя ничто иное, как функции в системных DLL. Любой процесс в системе обязательно имеет в своем адресном пространстве Ntdll.dll, где располагаются функции Native API - базовые функции низкоуровневой работы с системой, функции Kernel32.dll являются переходниками к более мощным функциям Ntdll, следовательно, целесообразно будет перехватывать именно функции Native API. Проблема в том, что Native API функции не документированы в SDK, но узнать модель их вызова можно дизассемблируя Kernel32.dll. Нельзя утверждать, что адреса функций в системных библиотеках не изменяются в зависимости от версии ОС, ее сборки либо даже конкретной ситуации. Это происходит из-за того, что предпочитаемая база образа библиотеки (dll preferred imagebase) является константой, которую можно изменять при компиляции. Более того, совсем не обязательно, что dll будет загружена именно по предпочитаемому адресу, - этого может не произойти в результате коллизии с другими модулями, динамически выделенной памятью и т.п. Поэтому статический импорт функций происходит по имени модуля и имени функции (либо ее номера - ординала), предоставляемой этим модулем. Загрузчик PE файла анализирует его таблицу импорта и определяет адреса функций, им импортируемых. В случае, если в таблице импорта указана библиотека, не присутствующая в контексте, происходит ее отображение в требуемый контекст, настройка ее образа и ситуация рекурсивно повторяется. В результате в требуемом месте определенной секции PE файла (имеющей атрибут "readable") заполняется массив адресов импортируемых функций. В процессе работы каждый модуль обращается к своему массиву для определения точки входа в какую-либо функцию. Следовательно, существуют два способа перехвата API вызовов: изменение точки входа в таблице импорта и изменение начальных байт самой функции (сплайсинг функции). 1. Изменение таблиц импорта. Этот метод выглядит так - определяется точка входа перехватываемой функции. Составляется список модулей, в настоящий момент загруженных в контекст требуемого процесса. Затем перебираются дескрипторы импорта этих модулей в поиске адресов перехватываемой функции. В случае совпадения этот адрес изменяется на адрес нашего обработчика. К достоинствам данного метода можно отнести то, что код перехватываемой функции не изменяется, что обеспечивает корректную работу в многопоточном приложении. Недостаток этого метода в том, что приложения могут сохранить адрес функции до перехвата, и затем вызывать её минуя обработчик. Также можно получить адрес функции, используя GetProcAddress из Kernel32.dll. Из-за этого существенного недостатка чаще пользуются вторым способом, который был выбран для реализации и в данном курсовом проекте. 2. Сплайсинг функции. Этот метод состоит в следующем - определяется адрес перехватываемой функции, и первые 5 байт её начала заменяются на длинный jmp переход по адресу обработчика перехвата. Если необходимо вызывать перехватываемую функцию, то перед заменой необходимо сохранить её начальные байты и перед вызовом восстанавливать их. Недостаток данного метода состоит в том, что если после восстановления начала функции произошло переключение контекста на другой поток приложения, то он сможет вызвать функцию, минуя перехватчик. Этот недостаток можно устранить, останавливая все побочные потоки приложения перед вызовом и запуская после вызова. Схематически перехват API функции можно изобразить так: Рис.4. Перехват API функции Теперь рассмотрим прототип функции ZwQueryDirectoryFile: NTSTATUS ZwQueryDirectoryFile(IN HANDLE FileHandle, IN HANDLE Event OPTIONAL, IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, IN PVOID ApcContext OPTIONAL, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass, IN BOOLEAN ReturnSingleEntry, IN PUNICODE_STRING FileName OPTIONAL, IN BOOLEAN RestartScan); Для нас важны параметры FileHandle, FileInformation и FileInformationClass. FileHandle - хэндл объекта директории, который может быть получен с использованием функции ZwOpenFile FileInformation - указатель на выделенную память, куда функция запишет необходимые данные FileInformationClass определяет тип записей в FileInformation. FileInformationClass перечислимого типа, но нам необходимы только четыре его значения, используемые для просмотра содержимого директории. FileDirectoryInformation:FileFullDirectoryInformation: FileBothDirectoryInformation:FileNamesInformation: Функция ZwQueryDirectoryFile записывает набор этих структур в буфер FileInformation. Во всех этих типах структур для нас важны только три переменных: NextEntryOffset - размер данного элемента списка Первый элемент расположен по адресу FileInformation + 0, а второй элемент по адресу FileInformation + NextEntryOffset первого элемента. У последнего элемента поле NextEntryOffset содержит нуль. FileName - это полное имя файла. FileNameLength - это длина имени файла Для сокрытия файла, необходимо сравнить имя каждой возвращаемой записи и имя файла, который мы хотим скрыть. Если мы хотим скрыть первую запись, нужно сдвинуть следующие за ней структуры на размер первой записи. Это приведет к тому, что первая запись будет затерта. Если мы хотим скрыть другую запись, мы можем просто изменить значение NextEntryOffset предыдущей записи. Новое значение NextEntryOffset будет нуль, если мы хотим скрыть последнюю запись, иначе значение будет суммой полей NextEntryOffset записи, которую мы хотим скрыть и предыдущей записи. Затем необходимо изменить значение поля Unknown предыдущей записи, которое предоставляет индекс для последующего поиска. Значение поля Unknown предыдущей записи должно равняться значению поля Unknown записи, которую мы хотим скрыть. Если нет ни одной записи, которую можно видеть, мы должны вернуть ошибку STATUS_NO_SUCH_FILE. 1 Рис.5. Блок-схема алгоритма сокрытия файлов 2.3 Описание функций драйвера Undocnt.h - заголовочный файл недокументированных функций и структур Windwos NT, использованных в программе Drvcomm.h - заголовочный файл определения структур Структура буфера запроса о сокрытии файла Собственный код IOCTL, с которым можно будет обращаться к драйверу при помощи вызова DeviceIOControl IOCTL_PROTECT_FILE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x01, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA), где, макрос CTL_CODE собирает информацию о типе запроса и на его основе генерирует код запроса Driver.c - главный файл драйвера, содержит все основные функции и точки входа, описанные в конструкторском разделе, а так же вспомогательные функции, реализующие сокрытие файлов. DriverEntry - основная главная точка входа в драйвер, внутри этой функции драйвер выполняет инициализацию для себя и для используемого устройства (в данном случае - «\FileSystem\NTFS». В этой же функции в случае удачи создания устройства создается символическая ссылка на него, устанавливаются обработчики основных функций драйвера (IRP_MJ_CREATE, IRP_MJ_CLOSE, IRP_MJ_DEVICE_CONTROL), но т.к. нет смысла полностью переопределять обработчик открытия файла (IRP_MJ_CREATE), следует взять адрес старого обработчика и в новом, после выполнения некоторых действий, вызывать его. Для получения старых обработчиков необходимо отключить защиту ядра от записи и функцией InterlockedExchange подменить их. DeviceControlRoutine - эта точка входа вызывается Диспетчером Ввода/вывода, она необходима, чтобы запросить драйвер инициировать некоторую операцию ввода/вывода. Соответственно, здесь, в случае получения от пользовательского приложения IOCTL_PROTECT_FILE вызываются функции скрытия (PrtAddRule) или открытия (PrtDelRule) файла. PrtFindRule - функция, просматривающая линейный список уже созданных правил на предмет совпадения имен. Так как представление имен файлов может быть различным, сравнивать имена нужно с конца. PrtAddRule / PrtDelRule - функции создания и удаления правил о сокрытии файлов. При создании или удалении правила, необходимо проверить его наличие, для этого вызывается функция PrtFindRule. Так как это критическая область, то в этой функции может находиться только один поток, значит необходимо использовать такое средство синхронизации, как семафор. NewDirectoryControl - обработчик запроса IRP_MJ_DIRECTORY_CONTROL, выполняющего определенную драйвером функцию для существующего файла (в данном случае его сокрытие) NewCreate - обработчик запроса IRP_MJ_CREATE, соответствующий запросу на обращение к некоторому файлу. При этом проверяется, есть ли правило о сокрытии данного файла в списке правил, и, если оно было найдено, то возвращается STATUS_UNSUCCESSFUL. Process_Names / Process_Both / Process_Full / Process_Dir - функции, вызываемые в NewDirectoryControl в зависимости от типа FileInformationClass. В них реализуется описанный выше алгоритм удаления файла из информации о директории, при наличии существования соответствующего правила.1 2.4 Описание функций пользовательского приложения Часть проекта, работающая в режиме пользователя, представляет собой визуальное приложение, которое предоставляет удобный интерфейс для работы с драйвером, а также реализует все необходимые функции для работы с ним. OpenDevice - возвращает handle устройства драйвераRequestDevice - функция получает handle драйвера и посылает ему драйверу с IOCTL кодом с помощью вызова DeviceIoControl DriverLoad - при загрузке создается ключ реестра с параметрами директории образа драйвера и его типа, потом вызывается функция NtLoadDriver. Если драйвер уже был загружен в память, то возвращается его handle, иначе возвращается STATUS_SUCCESS DriverUnload - при выгрузке драйвера из памяти вызывается функция NtUnloadDriver DriverHideObject - функция заполняет структуру request типа REQUEST_BUFFER, описанную выше, и передает управление функции RequestDevice 2.5 Взаимодействие драйвера и приложенияСхематически взаимодействие драйвера и приложения отображено в разделе «структура разрабатываемого программного продукта». Рассмотрим конкретные средства осуществления этого механизма. В функции DriverEntry выполняется регистрация рабочих процедур. Регистрация производится путем заполнения элементов массива MajorFunction. Индексом в этом массиве является коды IRP_MJ_xxx, то есть описанные числами типы пакетов IRP. Если драйвер считает необходимым обрабатывать IRP запросы какого-либо типа, то в соответствующем элементе массива MajorFuncrion он регистрирует соответствующую функцию (записывает ее адрес). Диспетчер ввода/вывода, ориентируясь на заполнение этого массива, вызывает нужные функции драйвера Dispatch Routines. В результате вызова в пользовательском приложении функции DeviceIoControl, код IRP пакета поступившего из Диспетчера ввода/вывода будет иметь код IRP_MJ_DEVICE_CONTROL, а одним из внутренних параметров данного IRP пакета будет указанный в вызове функции DeviceIoControl код IOCTL. Процедура DeviceControlRoutine, описанная в драйвере, предназначена для обработки запросов Диспечера ввода/вывода, которые он формирует в виде IRP пакетов. В драйвере реализована обработка IOCTL запроса IOCTL_PROTECT_FILE, уже описанного выше. 3. Технологический раздел 3.1 Выбор языка и среды программирования Сегодня существует большое количество как различных средств разработки, так и платформ. Наиболее используемые в настоящее время языки программирования: C++/MFC, Win32/C++, Visual Basic, Java, Delphi, C#. Выбор языка программирования сразу же был сделан в пользу C/C++. Будучи языком высокого уровня, он все же предоставляет программисту полный контроль над машиной, позволяет легко переходить на язык более низкого уровня (ассемблер). С++ является мировым стандартом для приложений, где нужно быстродействие и малый размер кода при достаточно глобальных масштабах проекта. Для написания драйвера использовался язык С, т.к. Windows XP не поддерживает использование C++ для компонентов ядра. Для этого имеется ряд причин: - отсутствие библиотеки времени исполнения (runtime library), а, следовательно, и определяемых в ней глобальных операторов new и delete; - отсутствие поддержки исключительных ситуаций C++; - нет поддержки инициализации глобальных экземпляров классов. Для разработки драйвера была использована специализированная среда для разработки драйверов - Driver Development Kit (DDK) для Windows XP Service Pack 1 от Microsoft Windows. В частности, утилита BUILD. Эта утилита позволяет создавать любой тип исполняемого файла, поддерживаемый NT с использованием командной строки. Для отладки драйвера использовался режим построения исполняемого файла - Checked build, который позволяет выводить трассировочную информацию с помощью функции DbgPrint(). Для ее просмотра использовалась программа Марка Руссиновича DebugView. Для разработки пользовательского приложения использовалась среда Microsoft Visual Studio 2005, поскольку она дает мощные и гибкие средства разработки программного продукта. Для создания максимально переносимого приложения для разработки было использовано WinAPI, что дает возможность пользовательскому приложению работать на всех компьютерах вне зависимости от того, установлен ли на нем FrameWork 2.x. Решающим фактором стало то, что WinAPI дает максимальную скорость выполнения, т.к. в любом случае все функции построены на API средствах Windows и являются лишь их «оберткой», что существенно снижает их эффективность. При разработке обеих частей проекта была реализована модульность для обеспечения необходимой структурированности, устранения громоздкости кода, и унификации отдельных частей программы с целью обеспечения возможности пользоваться фрагментами программы при написании других приложений и для удобства дальнейшего развития проекта. 3.2 Пользовательский интерфейс При запуске программы автоматически создается дерево файлов всех дисков NTFS на компьютере. Для загрузки драйвера в память нужно нажать на кнопку «загрузить». При успешной загрузке драйвера будет выдано соответствующее сообщение, в случае ошибки (например, если драйвер уже находится в памяти) пользователю будет выдан тип ошибки. Рис.7. Вид главного окна Для сокрытия файлов необходимо выбрать соответствующий файл из каталога файлов и перетащить его в правую сторону, либо нажать на верхнюю кнопку со стрелочкой влево. Если при закрытии приложения драйвер не был выгружен из памяти, то при последующем запуске все скрытые ранее фалы будут показываться в левом окне приложения. Все скрытые файлы хранятся в реестре в ветке HKEY_LOCAL_MACHINE\SYSTEM\Rootkit и удаляются оттуда либо при поступлении команды о снятии правила с файла. Для того, чтобы снять все правила, необходимо нажать на самую нижнюю кнопку и все файлы, находящиеся слева станут видимыми для пользователя. При сокрытии файлов необходимо помнить о том, что нельзя скрывать те файлы, которые используются в настоящий момент (!) или к ним возможно последующее обращение (!). Если система не сможет получить доступ к файлу, то для этого файла будут накапливаться необработанные сообщения, что приведет к краху системы. Рис.8. Вид директории до сокрытия файла DjvuReader.exe Рис.8. Вид директории после сокрытия файла DjvuReader.exe 3.3 Тестирование драйвера Для тестирования драйвера использовалась программа Driver Verifier, входящая в состав Driver Development Kit (DDK) для Windows XP Service Pack 1 от Microsoft Windows, которая проверяет правильность следующих тестов: 1. Операции с пулами памяти; 2. Корректность уровней IRQL, на которых выполняется код драйвера; 3. Обнаружение взаимоблокировок; 4. Выполнение DMA операций; 5. Стресс-тест (нехватка ресурсов); Рис.9. Диспетчер проверки драйверов Все тесты прошли успешно. Память в системе распределялась правильно, ошибок с ней не возникало. На нехватку ресурсов драйвер реагировал корректно. Нетипичные запросы к драйверу не обрабатывались им. Выводы В ходе разработки проекта были исследованы и проанализированы подходы к решению проблемы скрытия файлов. В результате работы над проектом создано программное средство, позволяющее скрывать файлы и папки в ОС Windows XP с помощью установки драйвера-фильтра файловой системы и обеспечивающее интерактивное взаимодействие с пользователем посредством приложения уровня пользователя. Данный программный продукт может использоваться как обычными пользователями для скрытия информации на компьютере, так и в ходе разработки системного программного обеспечения, поскольку возможно расширение функциональности созданной программы, путем добавления обработчиков соответствующих IRP - запросов в драйвер. Фильтр-драйвер был протестирован с помощью тестовых утилит из состава пакета DDK и отвечает всем современным требованиям, накладываемым ОС Windows на характеристики драйверов. Из недостатков реализованного проекта можно отметить невысокую степень защиты скрываемых данных - при перезагрузке системы в безопасном режиме, скрытые файлы и папки становятся снова видимыми. Эту проблему можно решить путем шифрования скрываемых данных, добавив реализацию соответствующих алгоритмов в пользовательское приложение, однако это, как было сказано в начале, выходит за рамки курсового проекта. Список используемой литературы 1. В.П. Солдатов, Программирование драйверов Windows. Изд. 2-е, перераб. И доп. - М.: ООО «Бином-Пресс», 2004 г. - 480 с.: ил. ISBN 5-9518-0099-4 2. MSDN Library, Copyright 1987-2007 Microsoft Corporation 3. Д.Н. Колесниченко, Rootkits под Windows,теория и практика программирования шапок-невидимок, позволяющих скрывать от системы данные, процессы, сетевые соединения, изд. «Наука и Техника»,2006 г 4. Г. Хоглунг, Дж. Батлер, Руткиты - внедрение в ядро Windows, изд. «Питер», 2007 г. 5. Шрайбер С.Б., Недокументированные возможности Windows 2000, Изд. 1-е, 2002 год, «Питер»
|