Делаю драйвер режима ядра, который позволяет процессу разблокировать для себя прямой доступ к портам ввода/вывода, использую Ke386IoSetAccessProcess и т.п. В этой связи возникло несколько вопросов: 1. Почему функция Ke386QueryIoAccessMap не требует в качестве аргумента указатель на объект "процесс", а Ke386IoSetAccessProcess требует? Значит ли это, что функция Ke386QueryIoAccessMap работает с TSS текущего процесса? 2. Действительно ли IOPM для всех процессов один?
Wolfgang IOPM несколько. Ke386QueryIoAccessMap по номеру IOPM выдает эту таблицу. Ke386IoSetAccessProcess устанавливает IOPM для процесса одну из уже существующих карт. Ke386QueryIoAccessMap работает с глобальным списком карт, не для текущего процесса. Противоположность Ke386QueryIoAccessMap - Ke386SetIoAccessMap.
Дизасмил эту функцию, она пирнимает два аргумента - указатель на буффер, куда скопируется IOPM и 1, если второй аргумент не 1, то копирования просто не произойдет Опять же, дизассемблриование дает основание полагать, что функция просто копирует IOPM из буфера, указатель на который передается функции в качестве аргумента, второй аргумент должен быть только единицей, номер одной из существующих IOPM нигде не фигурирует. Не исключаю возможности, что я неправильно что-то понял, но вопросы мои остаются в силе
Угу. Потому что пока только 1 IOPM существует =) Хотя насколько я понял M$ реализовала возможность оперировать не только с 1 картой. Если MapNumber == 0, тогда битовая карта полностью заполняется еденицами. MapNumber <= IOPM_COUNT тогда копируется PCR->TSS->IoMaps[MapNumber].IoMap, но тк карта одна, то и копируется только она. Угу. Да.
Тогда как объяснить тот факт, что в моей системе один процесс имеет прямой доступ к портам ввода/вывода, а остальные - нет?!?! Это -проверенный факт. И если Ke386QueryIoAccessMap работает с TSS текущего процесса, то как получается, что функция этв, будучи вызванной в контексте SYSTEM, срабатывает для моего процесса? Очевидно, я не уловил какой-то ключевой момент
Да этот-то материал от Four-F'а меня и сбил с толку! С помощью функций Ke386IoSetAccessProcess и Ke386IoSetIoAccessMap из драйвера в контексте процесса А я открываю прямой доступ к портам. Пробую доступ к портам из процесса Б, созданного после - исключение, пробую из процесса А - нет исключения. Как это можно объяснить??? Этот вопрос и не возник бы у меня, если бы мой механизм работал, но иногда он не срабатывает и порты остаются залоченными :-(
Wolfgang Так какой функцией пользуешься Ke386IoSetAccessProcess или Ke386IoSetIoAccessMap? Если тебе надо дать доступ всем процессам, то в статье выше описано ещё парочка способов.
IOPM действительно одна (точнее, изначально был предусмотрен массив этих карт, но его размер == 1), но вот поле Process->IopmOffset у каждого процесса своё. Если оно указывает на карту, то процесс ей пользуется, если нет, то соответственно не может пользоваться. Т.о. сначала надо установить IOPM, у потом для каждого процесса, которому она нужна, вызвать Ke386IoSetAccessProcess, чтобы она прописала поле Process->IopmOffset.
Этот код выполняется в контексте процесса, которому нужен доступ к портам ввода/вывода, IOPM с номером один заполнена нулями, табличка эта действительно содержит нули... но при обращении к портам процесс все равно вызывает исключение Code (Text): kal db "IOPM: %08X...", 10, 0 ... invoke PsGetCurrentProcess invoke Ke386IoSetAccessProcess, eax, 1 test al, al jnz create_done push STATUS_IO_PRIVILEGE_FAILED pop status create_done: invoke Ke386QueryIoAccessMap, 1, addr pIopm invoke DbgPrint, addr kal, pIopm[0] ... Уважаемый Four-F, в чем тут может быть причина?
В аттаче измененный DateTime из KmdKit. 1 - Только модифицирует и устанавливает новую IOPM (Ke386SetIoAccessMap). 2 - Только разрешает процессу её использовать (Ke386IoSetAccessProcess). У меня работает.
Можно тогда несколько вопросов? 1. Для чего выделяется постоянная неподкачиваемая память, если IOPM все равно лежит в другом месте и из выделенного буфера только один раз копируется? Code (Text): invoke MmAllocateNonCachedMemory, IOPM_SIZE P.s. имеет для PsGetCurrentProcess
Хороший вопрос Мне он тоже приходил в голову. Точного ответа я не знаю, но, IMHO, выделять некешируемую память здесь не имеет смысла. Единственное жесткое требование - она должна быть из неподкачиваемого пула. Возможно, исторические причины: тот, кто первым писАл этот код, делал это очень давно и, возможно, тогда это имело значение. Ну а все последователи делают тоже самое на всякий случай. Я тоже так сделал Упс... Конечно имеет. Я не обратил внимание на то, что указатель на процесс берется от PsGetCurrentProcess.
Тем не менее, почему-то не срабатывает на некоторых ХР-системах, проверяю обе IOPM, одна штатная - заполненная единичками, другая - сформированная мной, заполнена нулями. Видимо, по каким-то причинам не срабатывает Ke386IoSetAccessProcess :-( Что именно делает эта функция, помимо изменения поля в структуре EPROCESS? Чтобы эти изменения попали в TSS, нужно ли что-то еще предпринимать? Прилагаю свой небольшой исходник драйвера. Суть его работы - создание устройства, при открытии которого пользовательским процессом открывается доступ к портам. P.s. примечательно, что после некоторого количества запусков работать таки начинает
Code (Text): NTSTATUS DriverCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp){ ULONG pIopm[2048]; PEPROCESS pProc; RtlZeroMemory(pIopm, 0x2000); pProc = PsGetCurrentProcess(); Ke386IoSetAccessProcess(pProc, 1); Ke386SetIoAccessMap(1, pIopm); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } Обрати внимание на то, что Ke386SetIoAccessMap вызывается после Ke386IoSetAccessProcess.
Работает... теперь самое интересное - почему не работает мой пример... 1. Может быть, на момент загрузки драйвера (он у меня грузится автоматом при загрузке системы) еще нельзя заполнять альтернативную IOPL? 2. Важно ли вызывать сначала Ke386IoSetAccessProcess, а потом Ke386SetIoAccessMap?