Red de conocimiento informático - Material del sitio web - Cómo construir un controlador de filtro USB simple

Cómo construir un controlador de filtro USB simple

Este artículo se divide en tres partes para presentar cómo construir un controlador de filtro USB simple, incluidos "Principios básicos", "Implementación del programa" y "Uso de la instalación INF". El propósito de este artículo es esperar que después de que los lectores comprendan los principios básicos, puedan usar DriverStudio, la herramienta de desarrollo de controladores más popular y conveniente además de DDK, para implementar su propio controlador de filtro e instalarlo correctamente.

1. Principios básicos

Sabemos que WDM (y KDM) son jerárquicos. Al construir la pila de dispositivos, el administrador de IO puede adjuntar un objeto de dispositivo a otro objeto de dispositivo inicial. creado por el conductor. El IRP determinado por el controlador asociado con el objeto de dispositivo inicial también se enviará al controlador asociado con el objeto de dispositivo adicional. Este controlador adjunto es el controlador de filtro. Como se muestra en la figura de la derecha, los controladores de filtro se pueden insertar en cualquier nivel de la pila de dispositivos. El IRP emitido por el administrador de IO se pasará de arriba a abajo y se devolverá siguiendo la secuencia de la derecha. Por lo tanto, podemos utilizar el controlador de filtro para inspeccionar, modificar y completar los IRP que recibe, o para construir sus propios IRP.

El texto anterior es muy aburrido. Afortunadamente, los "predecesores" ya han escrito algunos ejemplos para que comprendamos mejor estos conceptos. Los lectores que hayan leído "Programación del modo de controlador de Windows" de Waltz Oney probablemente sepan que uno de los ejemplos proporcionados por Waltz Oney incluye un ejemplo sobre filtros USB (Capítulo 9, basado en esto, "Diseño de USB con ejemplo", John Hyde, autor de). (), implementó un controlador de filtro de teclado USB, que agregó una función "Interceptar" a este programa para procesar el Informe del teclado USB para lograr funciones específicas: Cuando el controlador está configurado en IRP_MJ_INTERNAL_DEVICE_CONTROL, el ejemplo de finalización Cuando el programa intercepta un Get_Report_Descriptor de un Dispositivo USB, el interceptor cambia el valor de USO en el Descriptor de "Teclado" a "Definido por el usuario" y luego lo devuelve al sistema.

Podemos inspirarnos un poco en este ejemplo. Por ejemplo, en Win2k, el sistema operativo accede exclusivamente al teclado. De esta manera, podemos hacerlo de libre acceso para los usuarios y también podemos interceptar otros Report_Descriptor. , redefine algunas claves para cumplir con requisitos especiales. Si está dispuesto a crear otro programa en modo de usuario, también puede pasar los valores de clave interceptados a su programa en modo de usuario para lograr cosas como Lenovo y Shida. Funciones prácticas en los teclados producidos por los principales fabricantes de computadoras nacionales.

2. Implementación del programa

Los ejemplos de Waltz Oney y John Hyde se han escrito con gran detalle. Los lectores pueden compilar y generar con éxito un controlador de filtro sin modificar un solo byte. El propósito de este artículo es utilizar el componente DriverStudio Driverworks para lograr la misma función.

Creo que cuando los lectores lean este artículo, ya sabrán mucho sobre DriverStudio. Como herramienta de desarrollo de controladores "rápida" basada en C++, DriverStudio encapsula básicamente todas las funciones de DDK. Su DriverWizard integrado en VC++ puede guiarlo fácilmente a través de todo el proceso de desarrollo de controladores de dispositivos. El código fuente del controlador de dispositivos se genera automáticamente según su tipo de hardware. y se proporcionan muchos programas de muestra. Por supuesto, estos ejemplos incluyen un marco de controlador de filtro USB. Nuestra práctica constante es hacer pleno uso del código compartido, gratuito y autorizado existente sin infringir los derechos de autor. Haremos modificaciones basadas en este ejemplo a continuación.

Nuestro propósito es crear un filtro inferior del pequeño controlador HID hidusb.sys, que está conectado al "dispositivo de interfaz humana" y modifica su valor de retorno interceptando el USB Get_Report_Descriptor cuando encuentra el descriptor. Cuando el uso sea "Teclado", cámbielo a "Definido por el usuario" para que podamos controlar completamente este teclado. El método específico es interceptar IRP_MJ_INTERNAL_DEVICE_CONTROL y verificar su código IOCTL y URB. Si se cumplen las condiciones para que el código de función IOCTL sea IOCTL_INTERNAL_USB_SUBMIT_URB y el código de función URB sea URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE, es decir, cuando el controlador superior envía una solicitud Get_Report_Descriptor, un Se establece la rutina de finalización. En este ejemplo de finalización. En el proceso, juzgaremos el valor de Uso. Cuando el Uso se cambie de "6 (Teclado)", lo cambiaremos a "0 (Definido por el usuario)".

Abra el directorio C:\Program Files\NuMega\DriverStudio\DriverWorks\Examples\wdm\usbfilt (el directorio específico varía según el directorio donde está instalado DriverStudio) y luego abra el archivo del proyecto usbfilt. .dsw. Primero echemos un vistazo al código.

El programa consta de dos clases, una es la clase Controlador y la otra es la clase Dispositivo.

La clase Driver incluye:

Función de entrada DriverEntry:

DECLARE_DRIVER_CLASS(UsbFilterDriver, NULL)

////////////// ////////////////////////////////////////////////// /// ////

// Entrada del controlador

//

NTSTATUS UsbFilterDriver::DriverEntry(PUNICODE_STRING RegistryPath)

{

T << "UsbFilterDriver::DriverEntry\n";

m_Unit = 0;

return STATUS_SUCCESS;

// La siguiente macro simplemente permite la compilación en el nivel de advertencia 4

// Si hace referencia a este parámetro en la función, simplemente elimine la macro.

UNREFERENCED_PARAMETER(RegistryPath);

}

Función AddDevice

NTSTATUS UsbFilterDriver::AddDevice(PDEVICE_OBJECT Pdo)

{

T << "UsbFilterDriver::AddDevice \n" ;

UsbFilterDevice * pFilterDevice = nuevo (

static_cast(NULL),

FILE_DEVICE_UNKNOWN,

static_cast< PCWSTR>( NULL),

0,

DO_DIRECT_IO

)

UsbFilterDevice(Pdo, m_Unit);

if (pFilterDevice)

{

NTSTATUS status = pFilterDevice->ConstructorStatus();

if ( !NT_SUCCESS(status) )

{

T << "Error al construir UsbFilterDevice"

<< (ULONG) m_Unit

<< " status = "

<< estado

<< "\n";

del

ete pFilterDevice;

}

else

{

m_Unit++;

}

estado de devolución;

}

else

{

T << "Error al asignar el dispositivo USBFilter"

<< (ULONG) m_Unit

<< "\n";

return STATUS_INSUFFICIENT_RESOURCES;

}

}

Estos dos fragmentos de código son básicamente similares al código generado automáticamente. La función de AddDevice es construir una instancia del filtro.

El código clave está en la clase Dispositivo. En esta clase, insertamos el filtro en la pila del dispositivo e interceptamos el IRP, usando nuestra propia rutina de finalización para implementar una funcionalidad específica.

Constructor de dispositivos

UsbFilterDevice::UsbFilterDevice(PDEVICE_OBJECT Pdo, Unidad ULONG):

KWdmFilterDevice(Pdo, NULL)

{

T << "UsbFilterDevice::UsbFilterDevice\n";

// Comprobar el estado del constructor

if ( ! NT_SUCCESS(m_ConstructorStatus) )

{

return;

}

// Recuerda nuestro número de unidad

m_Unit = Unidad;

// inicializa el dispositivo USB inferior

m_Usb.Initialize(this, Pdo);

NTSTATUS status = AttachFilter(&m_Usb); //Conecta el filtro

< p); > if(!NT_SUCCESS(estado))

{

m_ConstructorStatus = estado;

retorno;

}

SetFilterPowerPolicy();

SetFilterPnpPolicy();

}

En el DDK, usamos IoAttachDevice para insertar el objeto del dispositivo en la pila del dispositivo. DriverStudio encapsula esta función. En DriverStudio, otros controladores necesitan usar Inicializar para inicializar objetos e interfaces del dispositivo. Para los controladores de filtro, nuestra clave es adjuntarlos a la pila con Attachfilter.

Para la mayoría de los IRP como IRP_MJ_SYSTEM_CONTROL, todo lo que necesitamos hacer es usar PassThrough(Irp) para pasarlo directamente a la capa inferior de la pila de dispositivos sin realizar ningún trabajo. No enumeraremos estos códigos uno por uno. La siguiente parte es la clave de este artículo.

Sabemos que HIDUSB.SYS utiliza IOCTLL interno para emitir URB al controlador de clase USB (USBD) para leer datos. Luego, HIDUSB primero debe construir un IRP_MJ_INTERNAL_DEVICE_CONTROL, y su código de función IOCTL es IOCTL_INTERNAL_USB_SUBMIT_URB (URB emitido). IOCTL interno). Además, debido a que lo que queremos verificar y modificar es la descripción del informe de una determinada interfaz del teclado USB, la URB debe ser URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE, de la siguiente manera:

NTSTATUS UsbFilterDevice::InternalDeviceControl(KIrp I)

{

T << "UsbFilterDevice::InternalDeviceControl\n";

// Pasar a través de IOCTL que no envían una URB

//Nosotros no Ignóralo si estás interesado en IOCTL

if (I.IoctlCode() != IOCTL_INTERNAL_USB_SUBMIT_URB)

return DefaultPnp(I);

PURB p = I. Urb(CURRENT); // obtiene el puntero URB del IRP

//No es la URB que nos interesa, así que ignórala,

if ( p->UrbHeader.Function !=

URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE)

return DefaultPnp(I);

//El IRP que cumple con los requisitos está configurado para completar el rutina

return PassThrough (I, LinkTo(DeviceControlComplete), this);

}

Después de establecer las condiciones, implemente la rutina de finalización. Todas las inspecciones, modificaciones y otras acciones se completan en la rutina de finalización.

NTSTATUS UsbFilterDevice::DeviceControlComplete(KIrp I)

{

PURB p = I.Urb(CURRENT);

if( p)

{

//Intercepta la tabla de descripción devuelta por el dispositivo,

char* DescriptorBuffer = (char*)p->UrbControlDescriptorRequest.TransferBuffer;

//Apunta al tercer byte, que indica el valor del atributo de uso del dispositivo.

DescriptorBuffer += 3;

//Si el valor es 6, cámbielo a 0, 6 significa teclado HID, 0 significa dispositivo desconocido

//En el administrador de dispositivos, el teclado original compatible con HID ya no existe, reemplazado por dispositivos compatibles con HID

if ((*DescriptorBuffer&0xff) == 6)

*DescriptorBuffer = 0;

}

return I.Status();

}

Los lectores pueden consultar los ejemplos en DriverWorks, reemplazar (o modificar) directamente las dos funciones anteriores y luego compilarlas para obtener un controlador de filtro de teclado completo.

De hecho, siempre que sepamos qué acciones debemos realizar, solo necesitamos escribir una pequeña cantidad de código clave en DriverStudio para cumplir con nuestros requisitos. Para la mayor parte del resto del trabajo. Puede haber ejemplos como referencia o generados automáticamente por Driver Wizard.

Como se puede ver en lo anterior, solo necesitamos modificar estas dos funciones e interceptar el IRP apropiado para lograr nuestros requisitos específicos en la rutina de finalización. Como se mencionó al principio, también podemos interceptar otros IRP, interceptar otros URB o interceptar los valores de las teclas de teclados específicos y pasarlos al modo de usuario para facilitar la realización de las funciones de los teclados multifunción equipados con Lenovo. Shida, etc.

3. Utilice INF para instalar el controlador

Después de completar el controlador, debe instalarlo en el sistema para que funcione. En términos generales, debemos proporcionar un archivo inf a nuestro controlador para facilitar la instalación o el mantenimiento por parte del usuario. Para los principiantes, filtrar las informaciones de los controladores puede ser un poco complicado. Por lo tanto, para el controlador descrito en este artículo, proporcionamos un ejemplo de instalación de usbkey.inf en Win98. El texto después de ";" en el ejemplo es un comentario para facilitar la comprensión de los lectores.

; usbkey.INF

; instala un filtro de nivel inferior para un dispositivo de teclado HID

(c) Copyright 2001 SINO Co., Ltd.

;

[Versión]

;"CHICAGO" significa plataforma Win9x

Firma="$CHICAGO$"

;Nombre de clase del teclado

Class=HID

ClassGUID={745a17a0-74d3-11d0-b6fe-00a0c90f57da}

Proveedor del controlador, esta información será se mostrará en la página "General" de las propiedades del dispositivo

Provider=%USBDBE%

LayoutFile=layout.inf

; ventana de detalles del archivo

DriverVer=11/12/2001,4.10.2222.12

;[ControlFlags]

;ExcludeFromSelect = *

;Directorio de instalación del controlador, inf instalará nuestro controlador en el siguiente directorio

; Recuerde que debe haber una "s" después de Destinationdir

[DestinationDirs]

DefaultDestDir = 10,system32\drivers

;Clave de registro para agregar

[ClassInstall]

Addreg=HIDClassReg

[HIDClassReg]

HKR,,,,%HID.ClassName%

HKR,,Icono,,-20

;Fabricante

[ Fabricante]

%USBDBE%=USBDBE

[USBDBE]

;El ID del dispositivo al que queremos conectar el controlador de filtro.

Este ID puede obtenerse de la especificación IC, leerse usando hidview.exe o encontrarse en el registro HKLM\Enum\hid y elementos USB

% HID.DeviceDesc% = Keypad_Inst, USB\VID_05AF&PID_0805&MI_00

;Archivos a instalar y claves de registro a modificar

;Instalar controlador de llave USB

[Keypad_Inst]

CopyFiles=Keypad_Inst. CopyFiles

AddReg=Keypad_Inst.AddReg

[Keypad_Inst.CopyFiles]

hidusb.sys

hidparse.sys

hidclass.sys

usbfilt.sys

[Keypad_Inst.AddReg]

HKR,,DevLoader, ,*ntkern

HKR ,,NTMPDriver,,"hidusb.sys"

[Keypad_Inst.HW]

AddReg=Keypad_Inst.AddReg.HW

;Lowerfilters representa un nivel bajo controlador de filtro Si es un controlador de filtro de nivel superior, debe cambiarse a filtros superiores

[Keypad_Inst.AddReg.HW]

HKR,,"LowerFilters", 0x00010000," usbfilt.sys"

;Los archivos que deben instalarse y los lugares que deben modificarse en el registro

;Instalar USBHIDDevice

[USBHIDDevice]

CopyFiles=USBHIDDevice.Copy

AddReg=USBHIDDevice.AddReg

[USBHIDDevice.Copy]

hidclass.sys

hidusb.sys

hidparse.sys

[USBHIDDevice.AddReg]

HKR,,DevLoader,,*ntkern

HKR,,NTMPDriver,,"hidusb.sys"

;A continuación se definen las cadenas que deben reemplazarse cuando se usan en algunos de los lugares anteriores

[cadenas]

USBDBE = "SINO Co., Ltd."

HID.DeviceDesc = "SINO USB MultiKeyboard"

HID.HIDDeviceDesc = "Dispositivos de interfaz humana"

HID.DefaultDevice = "Dispositivo HID predeterminado"

HID.ClassName = "Dispositivos de entrada humana (HID)"

HID.SvcDesc = "Controlador de clase HID de Microsoft"

De hecho, la forma más sencilla de escribir inf es encontrar algunos archivos inf o ejemplos de dispositivos similares para modificar. Nuestro principio constante es hacer pleno uso de los recursos existentes sin infracciones.