wdm/wmi调用与实现

本文深入探讨了WMI(Windows Management Instrumentation)在驱动程序中的实现,包括WMI数据的动态提供、mof文件的创建与发布,以及驱动注册为WMI Provider的方法。此外,还介绍了如何通过mofcomp和wmimofck工具进行文件处理。文章以WDM驱动为例,详细阐述了如何处理WMI数据查询、方法调用和事件监听。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


1.  文档说明

本文重点介绍了WMI的客户端实现方法和驱动程序Provider的在多路径设备相关驱动中的实现方法。

 

2.  WMI简介

WMI(Windows  Management Instrumentation)windows管理规范是WBEM模型在windows系统中的实现。通过WMI可以访问、配置、管理和监视几乎所有本地和远程的windows资源。比如用户可以在远程计算机器上启动一个进程;设定一个在特定日期和时间运行的进程;远程启动计算机;获得本地或远程计算机的已安装程序列表;查询本地或远程计算机的Windows事件日志等等。

 

应用程序程序从驱动中获取数据主要通过两种方法实现。

方案一:应用程序通过调用DeviceIOControl调用驱动接口交互

应用程序通过符号链接名打开驱动设备,调用DeviceIOControl跟驱动交互。驱动程序需要注册驱动程序符号链接名,处理应用程序发送的请求。注册符号连接名会暴露在用户模式下,安全性差。驱动程序只能被动接收应用程序的命令,不能主动发送事件给应用程序。

方案二:应用程序和驱动程序通过WMI接口交互

应用程序调用统一的COM API来读取驱动提供的数据。驱动程序可以处理IRP_MJ_SYSTEM_CONTROL数据包。也可以使用WMILIB库来处理IRP,但需要注册回调函数处理应用程序的请求,在应用程序订阅事件后,驱动程序可以主动触发事件,并通知应用程序,可以双向交互。

 

WMI客户端与WMIProvider端是通过三种方式进行交互的。包括WMI数据的查询、Provider方法的调用和对Provider事件的监测。以下调研基于MPIO DDK中gendsm的实现。

 

 

3.  WDM/WMI实现基础

3.1.创建mof文件

3.1.1 编写mof文件

用户态应用程序与驱动程序的交互是通过mof类进行交互的。

Ø 用户态应用程序所能看到是通过mof中定义的类来查询驱动程序数据。

Ø 驱动程序通过mof类结构为应用程序提供数据。

在mof文件中可以定义WMI数据,方法和事件。以下三个实例分别定义了数据、方法和事件类。当然数据和方法可以定义在同一个类中,但事件需要定义单独的类。

[WMI,

Dynamic,

 Provider("WmiProv"),

 Description("Just have a datatest."),

 Locale("MS\\0x409"),

 guid("{90A3FD34-4CDD-40c0-B24D-605DDFCFF728}")]

class GENDSM_DATA_TEST

{

    [key,read]

     stringInstanceName;

    [read]boolean Active;

   

   [WmiDataId(1),

     read,

    Description("Identifier.")

    ] uint32Id;

};

 

[Dynamic,

 Provider("WMIProv"),

 WMI,

 Description("GENDSM WMI Methods") ,

 guid("{5EDEFDC3-12BB-499c-86EE-3ECA60725144}")

]

class GENDSM_METHODS_TEST

{

    [key,read]

    stringInstanceName;

    [read]boolean Active;

 

   [WmiMethodId(1),

     read,write,

    Implemented,

    Description("Clear path performance counters for the device.")

    ]

    voidGetStatus(

      [in,

      Description("in parameter")

      ]uint32unCount,

//       [in,

//       MaxLen(63)

//       Description("in parameter")

//      ]string StatusId,

            [out,

        Description("Status of the operation")

        ]uint32 Status);

};

 

[Dynamic,

 Provider("WMIProv"),

 WMI,

 Description("MultiPath EventLogger"),

 guid("{EED61148-32C6-4e0a-A156-8C4564E15511}"),

 locale("MS\\0x409")

]

class GENDSM_EVENT_TEST : WMIEvent

{

        [key,read]

        stringInstanceName;

 

        [read]

       boolean Active;

 

       

 

        //

        //Current system time at time of logging.

        //

       [WmiDataId(1),

         read,

        Description("Time Stamp"),

        WmiTimeStamp

        ] uint64 TimeStamp;

 

        //

        //Indicates severity of event being logged.

        //

       [WmiDataId(2),

        read,

       Values{"Fatal Error",

              "Error",

              "Warning",

              "Information"},

 

        DefineValues{"MPIO_FATAL_ERROR",

                    "MPIO_ERROR",

                    "MPIO_WARNING",

                    "MPIO_INFORMATION"},

 

       ValueMap{"1", "2", "3", "4"}

        ]uint32 Severity;

 

       [WmiDataId(3),

        read,

        Description("ErrorCode")

        ]uint32 ErrorCode;

 

        //

        //Description of event.

        //

       [WmiDataId(4),

        read,

       MaxLen(63),

       Description("Event Description")

        ]string EventDescription;

};

编写mof文件后可以使用mofcomp.exe–check  xx.mof文件进行语法检查。

 

3.1.2 WMI类限定符

如果一个类只是作为另一个类的数据项,不输出WMI数据块,则称为嵌入类。嵌入类只需要WMI和GUID两项限定符。如果定义为嵌入类,则不能从该类的实例读取数据。其他限定符有些是需要的而有些是可选的,详细如下:

 

Dynamic: 标示数据提供者动态提供类实例的数据,而不是在mof文件中静态提供。驱动注册的wmi类必须拥有此限定符。

Static:    由mof文件静态提供类实例数据,不能用在在驱动中注册的wmi类。

Provider(“WMIProv”): (需要的)标示类的提供者是一个WMI提供者。

WMI: (需要的)标示这个类是一个wmi类

Description(“docu”): (可选的)类得描述。

Guid: (需要的)WMI数据块的唯一标示,驱动在注册时想wmi发送这个值,wmi用Guid查询驱动mof文件中的数据定义。

Locale(“MS\\locale-identifer”): (可选的)指定Description的语言。

WmiExpense(expensevalue): (可选的)指定获取数据的cpu周期间隔

 

 

3.1.3 编写mof文件注意事项

Ø 在创建类中函数时,返回值必须为void,否则编译不过。

Ø 在定义数据块或消息块时,必须包含以下两项,否则无法生成类实例。

[key, read]

string InstanceName;

[read] boolean Active;

Ø 所有类GUID在使用过程中必须保持一致。

 

 

3.2.mof文件的发布

mof文件的发布就是将mof文件类添加到CIM类库中。在应用程序查询WMI类数据时,系统WMI可以把请求发送到相应的驱动中去执行。本部分的内容在msdsm中封装实现,此部分仅作参考。

3.2.1使用mofcomp注册类

mofcomp.exe是一个mof文件汇编器,可以执行语法检查,注册等多种功能。

(1)  mofcomp*.mof 可以将*.mof文件中的类添加到类库中。

 

 

3.2.2 由驱动注册mof文件类

由驱动注册mof文件有三种实现

1、   以bmf文件形式注册

bmf文件由mofcomp.exe–WMI –B:filename.bmf  filename.mof产生,需要在驱动的资源文件(.rc)文件中包含MofResourceMOFDATAfilename.bmf字符串,当驱动收到主功能码为IRP_MJ_SYSTEM_CONTROL副功能码为IRP_MN_REGINFO或IRP_MN_REGINFO_EX,Parameters.WMI.DataPath为WMIREGISTER注册请求时,可以以下面两种方式指定mof资源名称。

Ø 如果使用wmi库函数来处理wmi请求时,需要在回调函数DpWmiQueryReginfo中(回调函数在WMILIB_CONTEXT结构体中指定)指定mof资源名称。

实例代码如下(由wmimofck.exe –cwmi.c dsm.bmf自动产生):

NTSTATUS

WmiQueryWmiRegInfo(

   IN PDEVICE_OBJECT DeviceObject,

   OUT ULONG *RegFlags,

   OUT PUNICODE_STRING InstanceName,

   OUT PUNICODE_STRING *RegistryPath,

   OUT PUNICODE_STRING MofResourceName,

   OUT PDEVICE_OBJECT *Pdo

   )

/*++

 

Routine Description:

 

   This routine is a callback into the driver to retrieve the list of

   guids or data blocks that the driver wants to register with WMI. This

   routine may not pend or block. Driver should NOT call

   WmiCompleteRequest.

 

Arguments:

 

   DeviceObject is the device whose registration info is being queried

 

   *RegFlags returns with a set of flags that describe the guids being

       registered for this device. If the device wants enable and disable

       collection callbacks before receiving queries for the registered

       guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the

       returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case

       the instance name is determined from the PDO associated with the

       device object. Note that the PDO must have an associated devnode. If

       WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique

       name for the device.

 

   InstanceName returns with the instance name for the guids if

       WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The

       caller will call ExFreePool with the buffer returned.

 

   *RegistryPath returns with the registry path of the driver. The caller

        does NOT free this buffer.

 

   *MofResourceName returns with the name of the MOF resource attached to

       the binary file. If the driver does not have a mof resource attached

       then this can be returned as NULL. The caller does NOT free this

       buffer.

 

    *Pdo returns with the device object for thePDO associated with this

       device if the WMIREG_FLAG_INSTANCE_PDO flag is retured in

       *RegFlags.

 

Return Value:

 

   status

 

--*/

{

   struct DEVICE_EXTENSION * devExt = DeviceObject->DeviceExtension;

 

   //

   // Return the registry path for this driver. This is required so WMI

   // can find your driver image and can attribute any eventlog messages to

   // your driver.

   *RegistryPath = &WmiRegistryPath;

       

#ifndef USE_BINARY_MOF_RESOURCE

   //

   // Return the name specified in the .rc file of the resource which

   // contains the bianry mof data. By default WMI will look for this

   // resource in the driver image (.sys) file, however if the value

   // MofImagePath is specified in the driver's registry key

   // then WMI will look for the resource in the file specified there.

   RtlInitUnicodeString(MofResourceName,L"MofResourceName");

#endif

 

   //

   // Specify that the driver wants WMI to automatically generate instance

   // names for all of the data blocks based upon the device stack's

   // device instance id. Doing this is STRONGLY recommended sinceadditional

   // information about the device would then be available to callers.

   *RegFlags = WMIREG_FLAG_INSTANCE_PDO;

 

   //

   // TODO: Assign the physical device object for the device stack to *Pdo

   *Pdo = devExt->physicalDevObj;

 

   return(STATUS_SUCCESS);

}

在msdsm驱动中将MofResource填入DSM_WMILIB_CONTEXT传到下MPIO.SYS注册wmi类。

Ø 如果由driver来直接处理,则需要在驱动回传给Parameters.WMI.Buffer的WMIREGINFO结构体中指定mof资源名称。

 

2、   以动态链接库的dll的形式注册

Ø 编译mof文件

Ø 将编译过的mof问价内容包含在dll中(可以编译成dll)

Ø 在驱动的服务健下添加MofImagePath健。

 

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services

   \DriverName

       MofImagePath   "\SystemRoot\System32\Drivers\DriverNameMof.dll"

也可以写在驱动安装inf文件中

       ; This is the Services section for the driver
               [Driver_service_install_section]
               AddReg=Driver_AddReg
               
               ; This is the Services AddReg section declared above.
               [Driver_AddReg]
               HKR,,MofImagePath,,DriverMof.dll 

3、   将bmf二进制内容直接包含在驱动文件中

Ø 编译mof文件

Ø 使用wmimofck.exe工具将bmf文件产生十六进制的.x文件

Ø 在驱动源文件中用#include包含.x文件中的数据。

Ø 注册为支持MSWmi_MofData_GUID,即MSWmi_MofData_GUID为数据索引。

Ø 当驱动收到IRP_MN_QUERY_ALL_DATA或IRP_MN_QUERY_SINGLE_INSTANCE请求时就mof内容以MSWmi_MofData_GUID索引传给WMI。

 

 

 

3.3.3.3mofcomp工具

mofcomp可以将mof文件生成bmf文件,在build驱动过程中生成的bmf文件使用windows\system\wbem文件夹下mofcomp.exe工具生成。命令如下:

Ø  mofcomp.exe–WMI –B:filename.bmf  filename.mof

-wmi 进行windows驱动程序模式检查

-B 只创建二进制mof文件,不添加到DB

filename.bmf生成的二进制mof文件

filename.mof编写的类文件

Ø  mofcomp.exe–check filename.mof

可以只检查mof文件语法

Ø  mofcomp.exefilename.mof

将mof文件内容添加到CIM类库中。

 

3.4.3.4wmimofck工具

在DDK bin文件夹下的x86,IA64和AMD64文件夹下有不同系统的wmimofck.exe工具。

Ø wmimofck.exe –xwmi.txt dsm.bmf

可以将dsm.bmf文件中的二进制文件内容转换为十六进制存储在wmi.txt中。

Ø wmimofck.exe –hwmi.h dsm.bmf

可以将dsm.bmf二进制文件中定义的GUID、数据结构和方法标记等存在wmi.h头文件中。在MPIO DDK中也会产生wmi.h头文件。

Ø wmimofck.exe –cwmi.c dsm.bmf

可以生成WDM中的wmi执行代码模板。如果不是用在MPIO DDK中,而是单独写自己的wmi实现会比较有用。

Ø wmimofck.exe –hwmi.h –m dsm.bmf

添加-m可以在头文件中产生方法参数列表结构体,在.c文件中实现时会比较有用。

3.5.将驱动注册为WMIProvider

一个支持WMI的驱动必须先注册才能使它的数据和消息块被WMI客户端使用。注册过程有两个阶段。

1、 调用IoWMIRegistrationControl(IN PDEVICE_OBJECT DeviceObject, IN ULONGAction) Action = WMIREG_ACTION_REGISTER,WMI会发出主功能码为IRP_MJ_SYSTEM_CONTROL副功能码为IRP_MN_REGINFO或IRP_MN_REGINFO_EX的IRP。

2、 处理WMI发送的IRP_MN_REGINFO或IRP_MN_REGINFO_EX请求。参考以bmf文件形式注册。

 

在MSDSM驱动中,在MPIO.SYS中已封装将驱动注册为WMI Provider的部分,只需要修改mof文件内容,在驱动中实现mof类定义的功能即可。

3.6.build驱动时注意事项

 

在build驱动时,最好删除mof文件和wmi头文件。如果文件夹存在dsm.bmf,而更新后的mof文件中有错误,则无法正确编译出dsm.b

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值