Вятский государственный гуманитарный университет
Опубликован: 27.05.2013 | Доступ: свободный | Студентов: 2689 / 585 | Длительность: 09:18:00
Самостоятельная работа 6:

Функции для управления устройствами

< Лекция 10 || Самостоятельная работа 6: 123 || Лекция 11 >

Задание 5. Исследовать структуру DRIVER_OBJECT.

Указания к выполнению.

1. В предыдущем задании мы узнали адрес объекта драйвера, который отвечает за устройство HarddiskVolume1. Информацию об этом драйвере можно получить либо при помощи команды:

dt DRIVER_OBJECT 82373690

либо при помощи команды:

!drvobj 82373690

Воспользуемся вторым способом:


На рисунке показаны имя драйвера и объекты-устройства, которыми данный драйвер управляет. В частности, кроме устройства HarddiskVolume1, драйвер управляет устройством, которое описывается объектом DEVICE_OBJECT, расположенным по адресу 0x82373278.

2. Дополнительную информацию о драйверах можно получить, воспользовавшись утилитой Process Explorer. В ней следует выбрать процесс System и отобразить для него DLL (меню View – пункт Lower Pane View – DLL):


Задание 6. Исследовать структуру IRP.

Указания к выполнению.

1. Продолжим трассировку функции NtReadFile (мы остановились на строке 121 – вызов функции ObReferenceObjectByHandle) – клавиша F10.

Обратите внимание на переменную deviceObject (строка 135). Значение, которое в ней оказывается после вызова функции IoGetRelatedDeviceObject не совпадает с полученным нами в задании 3. Дело в том, что запрос к файлу проходит несколько драйверов на разных уровнях, и в переменную deviceObject помещается ссылка на драйвер верхнего уровня.

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

2. Найдите строку 517 – здесь происходит вызов функции IopAllocateIrp, которая выделяет память (но не заполняет) под структуру IRP. Поставьте в этой строке точку останова (нажмите F9):


И продолжите выполнение кода функции – нажмите F5. Управление должно перейти в точку останова на строку 517.

3. После выполнения функции IopAllocateIrp (нажмите клавишу F10) узнайте адрес переменной irp и просмотрите её содержимое либо при помощи команды:

dt irp address

либо при помощи команды:

!irp address

Предположим, адрес переменной irp равен 0x81efc008:


Из рисунка видно, что структура IRP пустая, и в ней 9 блоков стека (структур типа IO_STACK_LOCATION), 10-й блок, не заполненный, является текущим. Количество блоков стека указывается в поле StackSize структуры DEVICE_OBJECT, а определяется это количество системой; причем различаются малые IRP с одним блоком стека и большие IRP, количество блоков стека которых варьируется (подробнее см. [5, стр. 595]). В нашем случае мы имеем дело с большим IRP.

4. Далее по коду функции происходит заполнение структуры IRP (просмотрите заполнение полей самостоятельно).

Обратите внимание на поля UserIosb (блок статуса, строка 542), majorFunction (номер основной функции; в случае чтения он равен константе IRP_MJ_READ = 3, строка 558), UserBuffer (буфер чтения, строка 697).

5. В строке 725 происходит вызов функции IopSynchronousServiceTail, которая помещает сформированный IRP в очередь потока.

Перед вызовом этой функции просмотрите структуру IRP:

!irp 0x81efc008

Из рисунка видно, что последний блок стека сейчас заполнен:

  • MajorFunction = 3 (константа IRP_MJ_READ);
  • FileObject = 81FFF2F8 (адрес объекта FILE_OBJECT для файла input.txt);
  • Args = 50 (размер буфера).

Чтобы посмотреть структуру IO_STACK_LOCATION для данного блока стека, нужно из адреса текущего блока стека (выделен на рисунке) вычесть 0x24 (размер блока стека):

dt IO_STACK_LOCATION 0x81EFC1BC–0x24

Задание 7. Исследовать результаты операции чтения.

Указания к выполнению.

1. Выполните вызов функции IopSynchronousServiceTail (нажмите один раз F10).

Когда управление вернется к отладчику, операция чтения будет выполнена.

2. Просмотрите содержимое буфера чтения.

Адрес буфера равен 0x0012FF14 (переменная Buffer, см. Задание 2 данной лабораторной работы). Просмотреть его содержимое (в ASCII кодах) можно командой:

da 0x0012FF14

или (в байтах) командой:

db 0x0012FF14

3. Просмотрите содержимое блока статуса – переменную IoStatusBlock (тип IO_STATUS_BLOCK). Найти её адрес можно в окне Locals.


Поле Status, равное нулю, говорит о том, что операция выполнена успешно. В поле Information содержится количество прочитанных байт (0x20 = 32 байта).

Задания для самостоятельного выполнения

Задание 1. Выполнить трассировку функции NtWriteFile и найдите отличия от функции NtReadFile.

Указания к выполнению.

1. Для исследования функции ядра NtWriteFile создайте проект на основе примера из MSDN для WinAPI функции WriteFile.

Задание 2. Исследовать параметры безопасности объектов устройств.

Указания к выполнению.

1. В объекте DEVICE_OBJECT имеется поле SecurityDescriptor. Требуется по методике, изложенной в лабораторной работе 5 "Безопасность в Windows", исследовать дескриптор безопасности объекта устройства.

< Лекция 10 || Самостоятельная работа 6: 123 || Лекция 11 >
Екатерина Мезенцева
Екатерина Мезенцева
Россия
Анастасия Пахутина
Анастасия Пахутина
Россия, Москва, Московский Государственный Университет им.М.В.Ломоносова, 2009