zoukankan      html  css  js  c++  java
  • 【原创】《windows驱动开发技术详解》第4章实验总结一

    目录
    1 实验要求
    2 编写过程
      2.1 确立整体架构
        2.1.1 入口函数——DriverEntry
        2.1.2 自定义创建设备函数——CreateDevice
        2.1.3 卸载函数——DriverUnLoad
        2.1.4 IRP派遣函数
        2.1.5 DUMP函数
    3. 收获
     
    4. 完整代码
     
    正文
     
     
    1 实验要求
     

     
    2 编写过程
     
    2.1 确立整体架构
     
    2.1.1 入口函数——DriverEntry
     
    (1)作用
    • 初始化Driver_Object驱动对象, 注册调用函数入口包括DriverUnload,MajorFunction的相关IRP派遣函数IRP_MJ_CREATE、IRP_MJ_CLOSE、IRP_MJ_READ、IRP_MJ_WRITE
    • 创建设备对象
    (2)初学者会遇到的问题
    • 当源文件为CPP格式时,DriverEntry没有使用extern "C"声明,导致错误error MSB3030: 无法复制文件“D:D_DRIVERNT_Driver层次结构x64Win7DebugNT_Driver层次结构.sys”,原因是找不到该文件。
    • NTSTATUS的定义,主要是NT_SUCCESS
     
    2.1.2 自定义创建设备函数——CreateDevice
     
    (1)作用
    • 创建指定设备名和符号链接名的设备对象
    • IoCreateSymbolicLink将符号链接和设备名联系起来
    • 设置设备对象的Flags值DO_BUFFERED_IO和设备拓展对象中的deviceName和symbolicName,用于卸载函数等其他地方
    (2)初学者会遇到的问题
         ◆在初始化设备拓展结构体时,将其中的deviceName(类型为UNICODE_STRING)设置为devName(类型为UNICODE_STRING),用了RtlCopyUnicodeString复制函    数,结果复制失败。原因是DeviceExtension的deviceName为空,而它的类型UNICODE_STRING是一种结构体
    1 typedef struct _UNICODE_STRING {
    2     USHORT Length;
    3     USHORT MaximumLength;
    4 #ifdef MIDL_PASS
    5     [size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT * Buffer;
    6 #else // MIDL_PASS
    7     _Field_size_bytes_part_(MaximumLength, Length) PWCH   Buffer;
    8 #endif // MIDL_PASS
    9 } UNICODE_STRING;
    RtlCopyUnicodeString函数不会修改MaximumLength和Buffer,也就是说当MaximumLength小于源字符串的长度,那只能截取源字符串MaximumLength长度的字符了。
    对于解决方法,可以直接将devName赋值给结构体的deviceName,如下(不安全,因为如果devName内存释放了Buffer存储的地址就不合法了,而结构体的deviceName继续引用就会出问题);
     

     
    2.1.3 卸载函数——DriverUnLoad
     
    (1)作用
    • 删除设备对象以及对应的符号链接
    (2)初学者会遇到的问题
    • 定义卸载函数时未按照系统规定的函数指针类型定义,VOID DriverUnLoad(PDRIVER_OBJECT pDriverObject),要注意到函数的返回值是VOID(大写),形参类型是PDRIVER_OBJECT。
     
    2.1.4 IRP派遣函数
    (1)作用
    • 处理IRP
    (2)初学者会遇到的问题
    • 未认识到IRP派遣函数函数的原型是NTSTATUS DefaultDispatchRoutine(PDEVICE_OBJECT pDeviceObject, PIRP pIrp);函数名可以改变。
    2.1.5 DUMP函数
    (1)作用
    • 显示调试信息
    (2)初学者会遇到的问题
    • KdPrint对驱动对象或设备对象地址的显示,其调用为KdPrint(("Driver Address:%#010x ",pDriverObject));;用显示16进制的地址,8位加上0x总共10位,容易搞错
    • UNICODE_STRING的输出,KdPrint(("Driver HardwareDatabase:%S ", pDriverObject->HardwareDatabase->Buffer));容易忽略Buffer域
    3. 收获
     
    • 当你看着书,跟着书一步一步的走,你会觉得什么都掌握,但是当你开始打开IDE编码的时候会突然无从下手。重要的细节不经过实际的编码是掌握不牢的。
    • 就我自己的编码方法,我会把程序的整个框架先写出来,写接口,再写步骤注释,最后再按照注释完整写出代码,整个过程会清晰很多。
    • 编码的时候,不要一边盯着书,不会的要自己尽力回忆,再不会则写个注释标记一下,等所有东西写完之后再去看书检查,效果会更好,而且比较容易记录错误。
     
    4. 完整代码
      1 #include <NTDDK.h>
      2 //设备拓展结构体
      3 typedef struct {
      4     PDEVICE_OBJECT pDeviceObject; //指向自己
      5     UNICODE_STRING deviceName;    //设备名
      6     UNICODE_STRING symbolicName;    //符号链接
      7     PDEVICE_OBJECT  attachDevice;   //下层设备对象
      8 }DeviceExtension, *PDeviceExtension;
      9 //DUMP函数
     10 void dump(PDRIVER_OBJECT pDriverObject)
     11 {
     12     KdPrint(("------------------------------------------------------
    "));
     13     KdPrint(("Begin dump"));
     14     //打印调试信息
     15     KdPrint(("Driver Address:%#010x
    ",pDriverObject));
     16     KdPrint(("Driver Name:%S
    ", pDriverObject->DriverName.Buffer));
     17     KdPrint(("Driver HardwareDatabase:%S
    ", pDriverObject->HardwareDatabase->Buffer));
     18     PDEVICE_OBJECT pDeviceObject = pDriverObject->DeviceObject;
     19     KdPrint(("Driver first device:%#010x
    ", pDeviceObject));
     20     for (int i = 1; NULL != pDeviceObject; pDeviceObject = pDeviceObject->NextDevice,++i)
     21     {
     22         KdPrint(("the %d device
    ", i));
     23         KdPrint(("Device AttachedDevice:%#010x
    ", pDeviceObject->AttachedDevice));
     24         KdPrint(("Device NextDevice:%#010x
    ", pDeviceObject->NextDevice));
     25         KdPrint(("Device StackSize:%d
    ", pDeviceObject->StackSize));
     26         KdPrint(("Device's DriverObject:%#010x
    ", pDeviceObject->DriverObject));
     27     }
     28     KdPrint(("dump over
    "));
     29     KdPrint(("------------------------------------------------------
    "));
     30 }
     31 //创建设备对象
     32 NTSTATUS CreateDevice(PDRIVER_OBJECT pDriverObject, UNICODE_STRING &linkName, UNICODE_STRING &devName)
     33 {
     34     NTSTATUS status;
     35     PDEVICE_OBJECT pDeviceObject;
     36     PDeviceExtension pDevExt;
     37     //创建设备对象
     38     status = IoCreateDevice(pDriverObject, sizeof(DeviceExtension), &devName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);
     39     if (!NT_SUCCESS(status))
     40     {
     41         return status;
     42     }
     43     //创建符号链接
     44     status = IoCreateSymbolicLink(&linkName, &devName);
     45     if (!NT_SUCCESS(status))
     46     {
     47         //删除设备对象
     48         IoDeleteDevice(pDeviceObject);
     49         return status;
     50     }
     51     //设置设备对象
     52     pDeviceObject->Flags |= DO_BUFFERED_IO;
     53     pDevExt = (PDeviceExtension)(pDeviceObject->DeviceExtension);
     54     pDevExt->deviceName = devName;
     55     pDevExt->symbolicName = linkName;
     56     pDevExt->pDeviceObject = pDeviceObject;
     57     return STATUS_SUCCESS;
     58 }
     59 //返回值不能为NTSTATUS,为VOID
     60 VOID DriverUnLoad(PDRIVER_OBJECT pDriverObject) 
     61 {
     62     KdPrint(("Leave
    "));
     63     //删除设备对象
     64     //删除符号链接
     65     PDEVICE_OBJECT pcurDevice, pNextDevice; 
     66     pcurDevice = pDriverObject->DeviceObject;
     67     while (NULL != pcurDevice)
     68     {
     69         PDeviceExtension pDevExt = (PDeviceExtension)(pcurDevice->DeviceExtension);
     70         pNextDevice = pcurDevice->NextDevice;
     71         IoDeleteSymbolicLink(&pDevExt->symbolicName);
     72         IoDeleteDevice(pcurDevice);
     73         pcurDevice = pNextDevice;
     74     }
     75 }
     76 //IRP派遣函数
     77 NTSTATUS DefaultDispatchRoutine(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
     78 {
     79     //显示IRP类型
     80     KdPrint(("%d", pIrp->Type));
     81     pDeviceObject;
     82     return STATUS_SUCCESS;
     83 }
     84 extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegisterPath)
     85 {
     86     NTSTATUS status = STATUS_SUCCESS;
     87     UNICODE_STRING linkName,devName;
     88     KdPrint(("Create
    "));
     89     pRegisterPath;
     90     //注册调用函数入口
     91     pDriverObject->DriverUnload = DriverUnLoad;
     92     pDriverObject->MajorFunction[IRP_MJ_CREATE] =
     93         pDriverObject->MajorFunction[IRP_MJ_CLOSE] =
     94         pDriverObject->MajorFunction[IRP_MJ_READ] =
     95         pDriverObject->MajorFunction[IRP_MJ_WRITE] = DefaultDispatchRoutine;
     96     //创建设备对象
     97     RtlInitUnicodeString(&devName, L"\Device\C_1");
     98     RtlInitUnicodeString(&linkName, L"\??\C_1");
     99     status = CreateDevice(pDriverObject,linkName,devName);
    100     if (!NT_SUCCESS(status))
    101     {
    102         return status;
    103     }
    104         
    105     RtlInitUnicodeString(&devName, L"\Device\C_2");
    106     RtlInitUnicodeString(&linkName, L"\??\C_2");
    107     status = CreateDevice(pDriverObject, linkName, devName);
    108     if (!NT_SUCCESS(status))
    109     {
    110         IoDeleteSymbolicLink(&linkName);
    111         IoDeleteDevice(pDriverObject->DeviceObject);
    112         return status;
    113     }
    114     dump(pDriverObject);
    115     return status;
    116 }

    本文链接:http://www.cnblogs.com/cposture/p/4727222.html

  • 相关阅读:
    ZOJ 2604 Little Brackets DP
    js实现回放拖拽轨迹-------Day48
    Android蓝牙开发
    linux中的两个很重要的信号:SIGALRM信号和SIGCHID信号
    MySQL mysqldump数据导出详解
    JFinal redis cluster集群插件
    nginx平滑升级
    温故而知新-String类
    Linux环境变量具体解释
    android消息机制
  • 原文地址:https://www.cnblogs.com/cposture/p/4727222.html
Copyright © 2011-2022 走看看