当前位置:编程学习 > 网站相关 >>

Windows内核安全编程__Ramdisk源码解读

这篇文章来介绍一下WDK中提供的一个案例源码--Ramdisk虚拟磁盘。这个例子实现了一个非分页内存做的磁盘储存空间,并将其以一个独立磁盘的形式暴露给用户,用户可以将它格式化成一个Windows能够使用卷,并且像操作一般的磁盘卷一样对它进行操作。由于使用了内存作为虚拟的存储介质,使这个磁盘具有一个显著的特点,性能的提高。这个例子所使用的微软WDF驱动框架。
入口函数
1.入口函数的定义
任何一个驱动程序,不论它是一个标准的WDM驱动程序,还是使用WDF驱动程序框架,都会有一个叫做DriverEntry的入口函数,就好像普通控制台程序中的main函数一样。这个函数是这样声明的:
NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
    );
这个函数具有两个参数,其中一个是PDRIVER_OBJECT类型的指针。它代表了Windows系统为这个驱动程序所分配的一个驱动对象。这个驱动对象是Windows系统中对某个驱动的唯一标示。
DriverEntry的第二个参数是一个UNICODE字符串,它代表了驱动在注册表中的参数所存放的位置。由于每个驱动都是以一个类似服务的形式存在的,在系统注册表的HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services树下总有一个和驱动名字相同的子树用来描述驱动的一些基本信息,并提供一个可使用的存储空间供驱动存放自己的特有信息。
2.Ramdisk驱动的入口函数
在Ramdisk驱动代码的DriverEntry函数中只做了几件简单的事情,下面用代码加以说明:
NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
 )
{
    WDF_DRIVER_CONFIG config;
    KdPrint(("Windows Ramdisk Driver - Driver Framework Edition.\n"));
    KdPrint(("Built %s %s\n", __DATE__, __TIME__));

    WDF_DRIVER_CONFIG_INIT( &config, RamDiskEvtDeviceAdd );
    return WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, WDF_NO_HANDLE);
}
DriverEntry做的第一件事情是声明了一个WDF_DRIVER_CONFIG类型的变量config,并且在两句无关痛痒的输出语句之后,很快的使用WDF_DRIVER_CONFIG_INT初始化config变量。WDF_DRIVER_CONFIG_INIT结构通常用来说明这个驱动程序的一些可配置项,其中包括了这个驱动程序的EvtDriverDeviceAdd和EvtDriverUnload回调函数的入口地址,这个驱动程序在初始化时的一些标志和这个驱动程序在分配内存时所使用的tag值,WDF_DRIVER_CONFIG_INIT这个宏在初始化WDF_DRIVER_CONFIG类型的变量时会把用户提供的EvtDriverDeviceAdd回调函数的入口地址存入其中,并且初始化这个变量的其他部分。EvtDriverDeviceAdd回调函数是WDF驱动框架中的一个重要的回调函数,它用来在当即插即用管理器发现一个新的设备的时候对这个设备进行初始化操作,在这里我们可以将自己编写的RamDiskEvtDeviceAdd函数提供给系统作为本驱动的EvtDriverDeviceAdd回调函数。
在设置好了config变量后,DriverEntry直接调用了WdfDriverCreate并返回。WdfDriverCreate函数是使用任何WDF框架提供的函数之前必须调用的一个函数,用来建立WDF驱动对象。WdfDriverCreate函数的前两个参数就是DriverEntry传入的驱动对象(DriverObject)和注册表路径(RegisterPath),第三个参数用来说明这个WDF驱动对象的属性,这里简单的用WDF_NO_OBJECT_ATTRIBUTES说明不需要特殊的属性。第四个变量是之前初始化过的WDF_DRIVER_CONFIG变量,第四个参数是一个输出结果。
调用这个函数之后,前面初始化过的config变量中的EvtDriverDeviceAdd回调函数--RamDiskEvtDeviceAdd就和这个驱动挂起钩来,在今后的系统运行中,一旦发现了此类设备,RamDiskEvtDeviceAdd就会被Windows的Pnp manager调用,这个驱动自己的处理流程也就要上演了。
EvtDriverDeviceAdd函数
这里所说的EvtDriverDeviceAdd函数是WDF驱动模型中的名词,对应到传统的WDM驱动模型中就是WDM中的AddDevice函数。在本驱动中RamDiskEvtDeviceAdd作为一EvtDriverDeviceAdd函数在DriverEntry中被注册,在DriverEntry函数执行完毕之后,这个驱动就只依靠RamDiskEvtDeviceAdd函数和系统保持联系了。正如上一节所说的,系统在运行过程中一旦发现了这种类型的设备,就会调用RamDiskEvtDeviceAdd函数。下面对这个函数进行分析。
首先来看RamDiskEvtDeviceAdd的定义
NTSTATUS RamDiskEvtDeviceAdd(
       IN WDFDRIVER Driver,
       IN PWDFDRIVER_INIT DeviceInit
);
这个函数的返回值是NTSTATUS类型,可以根据实际函数的执行结果选择返回表示正确的STATUS_SUCCESS或者其他代表错误的返回值。这个函数的第一个参数是一个WDFDRIVER类型的参数,在这个例子中不会使用这个参数;第二个参数是一个WDFDRIVER_INIT类型的指针,这个参数是WDF驱动模型自动分配出来的一个数据结构,专门传递给EvtDriverDeviceAdd类函数用来建立一个新设备。下面具体来看代码:
2.局部变脸的声明
    //将要建立的设备对象的属性描述变量
    WDF_OBJECT_ATTRIBUTES   deviceAttributes;
    //函数返回值
    NTSTATUS                status;
    //将要建立的设备
    WDFDEVICE               device;
    //将要建立的队列对象的属性描述变量
    WDF_OBJECT_ATTRIBUTES   queueAttributes;
    //将要建立的队列配置变量
    WDF_IO_QUEUE_CONFIG     ioQueueConfig;
    //这个设备所对应的设备扩展
    PDEVICE_EXTENSION       pDeviceExtension;
    //将要建立的队列扩展域的指针
    PQUEUE_EXTENSION        pQueueContext = NULL;
    //将要建立的队列
    WDFQUEUE                queue;
    //设备名称
    DECLARE_CONST_UNICODE_STRING(ntDeviceName, NT_DEVICE_NAME);
    //确保函数可以使用分页内存
    PAGED_CODE();
    //避免编译警告
    UNREFERENCED_PARAMETER(Driver);
3.磁盘设备的创建
EvtDriverDeviceAdd类函数的一个重要任务是创建设备,而它的WDFDEVICE_INIT类型参数就是用来做这样的事情,在创建设备之前需要按照开发人员的思想对WDFDEVICE_INIT变量进行进一步的加工,使创建的设备能够达到想要的效果。由于这里的设备首先需要一个名字,这是因为这个设备将会通过这个名字暴露给应用层并且被应用层所使用,一个没有名字的设备是无法在应用层使用的。另外需要将这个设备的类型设置为FILE_DEVICE_DISK,这是因为所有的磁盘设备都需要使用这个设备类型。将这个设备的I/O类型设置为Direct方式,这样在将读,写和DeviceIoControl的IRP发送到这个设备时,IRP所携带的缓冲区将可以直接被使用。将Exclusive设置为FALSE这说明这个设备可以被多次打开。
    //首先需要为这个设备指定一个名称,这里使用刚才声明的UNICODE_STRING
    status = WdfDeviceInitAssignName(DeviceInit, &ntDeviceName);
    if (!NT_SUCCESS(status)) {
        return status;
    }
    //接下来需要对这个设备进行一些属性设置,包括设备类型,IO操作类型和设备的排他方式
    WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_DISK);
    WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect);
    WdfDeviceInitSetExclusive(DeviceInit, FALSE);
    //下面来指定这个设备的设备扩展
    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_EXTENSION);
    //下面我们还将利用这个WDF_OBJECT_ATTRIBUTES类型的变量来指定这个设备的清除回调函数,
    //这个WDF_OBJECT_ATTRIBUTES类型的变量将会在下面建立设备时作为一个参数传进去
    deviceAttributes.EvtCleanupCallback = RamDiskEvtDeviceContextCleanup;
    //到这里所有的准备工作都已就绪,我们可以开始真正的建立这个设备了,
    //建立出的设备被保存在devi

补充:综合编程 , 安全编程 ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,