加入收藏 | 设为首页 | 会员中心 | 我要投稿 东莞站长网 (https://www.0769zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 系统 > 正文

04内核-驱动对象

发布时间:2021-03-05 04:47:56 所属栏目:系统 来源:网络整理
导读:驱动对象 驱动程序:就是一个 .sys 模块, 驱动对象:则是 .sys 被加载到内核中的实例化出来的对象,用于表示这个驱动模块. Windows内核使用 DRIVER_OBJECT 结构体来描述一个驱动对象. 虽然Windows内核源码使用C语言编写,但也使用了面向对象的思想. 在面向对象

NT 设备名 - 设备名一般格式为"Device自定义设备名",此格式的名字一般是用于传递函数IoCreateDevice所要求给出的设备名. 这个设备名可以在内核下使用,但是用户层程序无法使用

  • DOS设备名 - 设备名一般格式为:"DosDevices自定义设备名",此格式的名字一般用户传递给函数IoCreateSymbolLinkName 的参数,后面这个函数的功能是为一个NT设备名创建一个用户层能够使用的符号链接名.

    符号链接的创建和销毁

  • IoCreateSymbolicLink - 为一个NT设备名链接到一个DOS设备名,DOS设备名可供用户层程序使用.

  • IoDeleteSymbolicLink - 删除一个DOS设备名.

  • 在用户层中打开设备

    当驱动对象创建了设备对象,并且设备对象也建立了DOS符号链接:

    // 驱动程序入口函数
    NTSTATUS DriverEntry(DRIVER_OBJECT* driver,UNICODE_STRING* path) {
    ??? driver->DriverUnload = NULL;
    ?
    ??? UNICODE_STRING ntDeviceName;
    ??? RtlInitUnicodeString(&ntDeviceName,L"Devicedev_test_1");
    ??? DEVICE_OBJECT* device;
    ?
    ??? NTSTATUS ret;
    ?
    ??? // 创建设备对象
    ??? ret = IoCreateDevice(driver,/*用于创建设备对象的驱动对象*/
    ???????????????????????? 0,/*扩展数据大小*/
    ???????????????????????? &ntDeviceName,? /*设备对象的NT设备名*/
    ???????????????????????? FILE_DEVICE_UNKNOWN,? /*设备对象的类型*/
    ???????????????????????? 0,? /**/
    ???????????????????????? 0,/**/
    ???????????????????????? &device/*被创建出来的设备对象*/);
    ??? if (!NT_SUCCESS(ret)) {
    ??????? return ret;
    ?? }
    ?
    ??? UNICODE_STRING dosDeviceName;
    ??? RtlInitUnicodeString(&dosDeviceName,L"DosDevicedev_test_1");
    ??? // 为NT设备名创建一个DOS符号链接名.
    ??? IoCreateSymbolicLink(&dosDeviceName,&ntDeviceName);
    }

    上面的代码创建的DOS设备名为:dev_test_1,(DosDevice只是一个前缀). 那么在三环中,可以通过以下方式打开此DOS设备:

    file = CreateFileW(L"\.dev_test_1",/*设备名*/
    ?????????????????? GENERIC READ | GENERIC WRITE,/*设备的打开后的操作权限*/
    ?????????????????? 0,
    ?????????????????? NULL,
    ?????????????????? OPEN_EXISTING,
    ?????????????????? 0,
    ?????????????????? NULL);

    派遣函数和IRP

    派遣函数实则就是当设备接收到了IO请求之后被调用来处理IO请求的函数.

    例如:

    file = CreateFileW(L"\.dev_test_1",
    ?????????????????? NULL);

    上述代码打开了一个设备对象,然后保存在驱动对象中派遣函数数组MajorFunction的第IRP_MJ_CREATE项就会被调用,如果这个元素被设置为NULL,则不会被调用,CreateFile也将调用失败. 调用此函数后,系统会将CreateFile传递的参数传递给派遣函数. 但派遣函数的原型(参数列表)中却没有这些形参:

    typedef
    NTSTATUS DRIVER_DISPATCH (
    ?? _In_ struct _DEVICE_OBJECT *DeviceObject,/*设备对象*/
    ?? _Inout_ struct _IRP *Irp /*IRP*/
    ?? );

    上面的代码就是所有派遣函数的原型,只有一个设备对象,和IRP结构体指针两个参数. 那么在用户层中传递过来的参数在哪里传递?

    系统其实已经将这些参数保存在了IRPIO_STACK_LOCALTION结构中.

    因此,IRP实际就是一个用户保存用户层传递进来的参数. 这些参数有多种,而且,对于不同的IO请求,会有不同的参数,而无论什么IO请求,多少个参数,都只能通过此结构体来保存,因此这个结构体比较庞大.

    在MSDN的文档中,专门有介绍不同的IO请求下,参数保存在IRP结构体中哪个字段:

    04内核-驱动对象

    04内核-驱动对象

    IO_STACK_LOCATION

    任何内核模式程序在创建一个IRP时,同时还创建了一个与之关联的IO_STACK_LOCATION结构数组:数组中的每个堆栈单元都对应一个将处理该IRP的驱动程序。 IRP的头部有一个当前IO_STACK_LOCATION的数组索引,同时也有一个指向该IO_STACK_LOCATION的指针。索引是从1开始,没有0。当驱动程序准备向次低层驱动程序传递IRP时可以调用IoCallDriver例程,它其中的一个工作是递减当前IO_STACK_LOCATION的索引,使之与下一层的驱动程序匹配。但该索引不会设置成0,如果设置成0,系统将会崩溃。就是说,最底层的驱动程序不会调用IoCallDriver例程。

    这个数组一般是紧随IRP结构体之后. 通过IoGetCurrentIrpStackLocation 函数就能过获取到当前设备的IO栈.

    IRP处理过程

    IRP处理概览(例子)

    下图是在用户层中打开文件时的过程(例如打开D:1.txt)

    (编辑:东莞站长网)

    【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读