Фильтр драйвера и DeviceIoControl
От: PR0m  
Дата: 23.09.04 10:09
Оценка:
Всем привет.

Сразу оговорюсь — в области драйверов я новичок
Пишу верхний фильтр (WDM) для устройства с использованием DriverWorks3.1.
Первым делом решил попробовать поуправлять внутренними переменными класса-устройства
RWHookDevice : public KWdmFilterDevice{... private: DWORD m_dwTest; ...};
через DeviceIoControl(...). Определил два кода — один для записи этой переменной, другой для чтения:

#define RWHOOKDRIVER_IOCTL_801 CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define RWHOOKDRIVER_IOCTL_802 CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)


Хэндлер для DeviceControl(KIrp I) выглядит так:

#define RWHOOKDRIVER_IOCTL_801    0x801
#define RWHOOKDRIVER_IOCTL_802    0x802

NTSTATUS RWHookDevice::DeviceControl(KIrp I)    
{ 
    NTSTATUS status;
    char bPassToLowerDev = 0;

    t <<"Entering RWHookDevice::DeviceControl\n";

    switch (I.IoctlCode())
    {
    // Свои управляющие коды обслуживаем на месте и сразу завершаем IRP
        case RWHOOKDRIVER_IOCTL_801:
            status = RWHOOKDRIVER_IOCTL_801_Handler(I);
            break;

        case RWHOOKDRIVER_IOCTL_802:
            status = RWHOOKDRIVER_IOCTL_802_Handler(I);
            break;

    // Остальные упр.коды отправляем ниже
        default:
            bNotPassToLowerDev = 1;
            status = PassThrough(I);
            break;
    }

    if( !bPassToLowerDev )
        return I.PnpComplete(status);
    else
        return status;
}



Хэндлеры для кодов RWHOOKDRIVER_IOCTL_801,RWHOOKDRIVER_IOCTL_802:

///////////////////////////////////////////////////////////////////////
// Чтение m_dwTest
///////////////////////////////////////////////////////////////////////
NTSTATUS RWHookDevice::RWHOOKDRIVER_IOCTL_801_Handler(KIrp I)
{
    NTSTATUS status = STATUS_SUCCESS;

    t << "Entering TestDriverDevice::RWHOOKDRIVER_IOCTL_801_Handler, " << I << "\n";

    if( I.IoctlOutputBufferSize() < sizeof(DWORD) )
        return STATUS_INVALID_PARAMETER;

    DWORD* pOutBuf = (DWORD*)I.IoctlBuffer();
    if( pOutBuf != NULL )
    {
        *pOutBuf = m_dwTest;
        I.Information() = sizeof(DWORD);
    }
    else
    {
        t << "NULL out buffer pointer!!!\n";
        I.Information() = 0;
        status = STATUS_INVALID_PARAMETER;
    }
    return status;
}

///////////////////////////////////////////////////////////////////////
// Запись m_dwTest
///////////////////////////////////////////////////////////////////////
NTSTATUS RWHookDevice::RWHOOKDRIVER_IOCTL_802_Handler(KIrp I)
{
    t << "Entering TestDriverDevice::RWHOOKDRIVER_IOCTL_802_Handler, " << I << "\n";

    if( I.IoctlInputBufferSize() < sizeof(DWORD) )
        return STATUS_INVALID_PARAMETER;

    DWORD* pOutBuf = (DWORD*)I.IoctlBuffer();

    if( pOutBuf == NULL )
    {
        t << "NULL in buffer pointer!!!\n";
        I.Information() = 0;
        return STATUS_INVALID_PARAMETER;
    }

    m_dwTest = *pOutBuf;
    I.Information() = 0;

    return STATUS_SUCCESS;
}


Для user-mode приложения определил пару функций:
FILTERDLL_API BOOL RwhWriteTestValue(HANDLE hDevice,DWORD dwValue)
{
    if( hDevice == INVALID_HANDLE_VALUE )
        return FALSE;
    OVERLAPPED ovl = {0};
    BOOL bRes = FALSE;
    DWORD dwBytesReturned;

    __try
    {
        ovl.hEvent = ::CreateEvent(NULL,TRUE,FALSE,NULL);
        bRes = ::DeviceIoControl(
            hDevice,
            RWHOOKDRIVER_IOCTL_802,
            &dwValue,
            sizeof(DWORD),
            NULL,
            0,
            &dwBytesReturned,&ovl);
    }
    __finally
    {
        ::CloseHandle(ovl.hEvent);
    }
    return bRes;
}

FILTERDLL_API BOOL RwhReadTestValue(HANDLE hDevice,LPDWORD pdwValue)
{
    if( hDevice == INVALID_HANDLE_VALUE )
        return FALSE;

    OVERLAPPED ovl = {0};
    BOOL bRes = FALSE;
    DWORD dwValue,dwBytesReturned;

    __try
    {
        ovl.hEvent = ::CreateEvent(NULL,TRUE,FALSE,NULL);
        bRes = ::DeviceIoControl(
            hDevice,
            RWHOOKDRIVER_IOCTL_801,
            NULL,
            0,
            &dwValue,
            sizeof(DWORD),
            &dwBytesReturned,
            &ovl);
        if( bRes )
            *pdwValue = dwValue;
    }
    __finally
    {
        ::CloseHandle(ovl.hEvent);
    }
    return bRes;
}


А проблема собстно в том, что запись проходит успешно, а при чтении выводится отладочное сообщение из драйвера
"NULL out buffer pointer!!!\n" ..., то бишь почему-то в драйвер не передаётся адрес выходного буфера, куда нужно вернуть значение
m_dwTest.
Работаю под WinXP SP2. Пробовал компилить под DDK_2K и DDK_XP с одинаковым результатом. С установкой и удалением фильтра проблем нет.
Ставлю на communications Port (COM-порты).

Где ж тут собака закопана?

С уважением, Роман.
Re: Фильтр драйвера и DeviceIoControl
От: PR0m  
Дата: 23.09.04 12:00
Оценка:
Вопрос снимается
В DeviceControl передавал неправильные значения управляющих кодов.
Re: Фильтр драйвера и DeviceIoControl
От: Геннадий Майко США  
Дата: 23.09.04 12:13
Оценка:
Здравствуйте, PR0m, Вы писали:

PR>Сразу оговорюсь — в области драйверов я новичок

PR>Пишу верхний фильтр (WDM) для устройства с использованием DriverWorks3.1.
PR>Первым делом решил попробовать поуправлять внутренними переменными класса-устройства
PR>RWHookDevice : public KWdmFilterDevice{... private: DWORD m_dwTest; ...};
PR>через DeviceIoControl(...). Определил два кода — один для записи этой переменной, другой для чтения:

PR>
PR>#define RWHOOKDRIVER_IOCTL_801 CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
PR>#define RWHOOKDRIVER_IOCTL_802 CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)
PR>



PR>Хэндлер для DeviceControl(KIrp I) выглядит так:


PR>
PR>#define RWHOOKDRIVER_IOCTL_801    0x801
PR>#define RWHOOKDRIVER_IOCTL_802    0x802

PR>NTSTATUS RWHookDevice::DeviceControl(KIrp I)    
PR>{ 
PR>    NTSTATUS status;
PR>    char bPassToLowerDev = 0;

PR>    t <<"Entering RWHookDevice::DeviceControl\n";

PR>    switch (I.IoctlCode())
PR>    {
PR>    // Свои управляющие коды обслуживаем на месте и сразу завершаем IRP
PR>        case RWHOOKDRIVER_IOCTL_801:
PR>            status = RWHOOKDRIVER_IOCTL_801_Handler(I);
PR>            break;

PR>        case RWHOOKDRIVER_IOCTL_802:
PR>            status = RWHOOKDRIVER_IOCTL_802_Handler(I);
PR>            break;

PR>    // Остальные упр.коды отправляем ниже
PR>        default:
PR>            bNotPassToLowerDev = 1;
PR>            status = PassThrough(I);
PR>            break;
PR>    }

PR>    if( !bPassToLowerDev )
PR>        return I.PnpComplete(status);
PR>    else
PR>        return status;
PR>}
PR>

--
Здесь немного странно. Метод Kirp.IoctlCode(), судя по исходному коду, должен вернуть "полные" IOCTL коды (как в define'e в первом примере кода) и они никак не дожны быть равны тем определениям, которые используются в функции DeviceControl (второй пример кода).

Если используются вторые (что очень вероятно, судя по сообщениям отладчика), то 2 младших бита будут интерпретироваться системой как METHOD_IN_DIRECT (для 0x801) и как METHOD_OUT_DIRECT (для 0x802), а не как METHOD_BUFFERED (как в первом define).

Так какие IOCTL коды таки используются у Вас?

С уважением,
Геннадий Майко.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.