目录
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_DRIVER\NT_Driver层次结构\x64\Win7Debug\NT_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是一种结构体
 typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
#ifdef MIDL_PASS
[size_is(MaximumLength / ), length_is((Length) / ) ] USHORT * Buffer;
#else // MIDL_PASS
_Field_size_bytes_part_(MaximumLength, Length) PWCH Buffer;
#endif // MIDL_PASS
} 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\n",pDriverObject));;用显示16进制的地址,8位加上0x总共10位,容易搞错
  • UNICODE_STRING的输出,KdPrint(("Driver HardwareDatabase:%S\n", pDriverObject->HardwareDatabase->Buffer));容易忽略Buffer域
3. 收获
 
  • 当你看着书,跟着书一步一步的走,你会觉得什么都掌握,但是当你开始打开IDE编码的时候会突然无从下手。重要的细节不经过实际的编码是掌握不牢的。
  • 就我自己的编码方法,我会把程序的整个框架先写出来,写接口,再写步骤注释,最后再按照注释完整写出代码,整个过程会清晰很多。
  • 编码的时候,不要一边盯着书,不会的要自己尽力回忆,再不会则写个注释标记一下,等所有东西写完之后再去看书检查,效果会更好,而且比较容易记录错误。
 
4. 完整代码
 #include <NTDDK.h>
//设备拓展结构体
typedef struct {
PDEVICE_OBJECT pDeviceObject; //指向自己
UNICODE_STRING deviceName; //设备名
UNICODE_STRING symbolicName; //符号链接
PDEVICE_OBJECT attachDevice; //下层设备对象
}DeviceExtension, *PDeviceExtension;
//DUMP函数
void dump(PDRIVER_OBJECT pDriverObject)
{
KdPrint(("------------------------------------------------------\n"));
KdPrint(("Begin dump"));
//打印调试信息
KdPrint(("Driver Address:%#010x\n",pDriverObject));
KdPrint(("Driver Name:%S\n", pDriverObject->DriverName.Buffer));
KdPrint(("Driver HardwareDatabase:%S\n", pDriverObject->HardwareDatabase->Buffer));
PDEVICE_OBJECT pDeviceObject = pDriverObject->DeviceObject;
KdPrint(("Driver first device:%#010x\n", pDeviceObject));
for (int i = ; NULL != pDeviceObject; pDeviceObject = pDeviceObject->NextDevice,++i)
{
KdPrint(("the %d device\n", i));
KdPrint(("Device AttachedDevice:%#010x\n", pDeviceObject->AttachedDevice));
KdPrint(("Device NextDevice:%#010x\n", pDeviceObject->NextDevice));
KdPrint(("Device StackSize:%d\n", pDeviceObject->StackSize));
KdPrint(("Device's DriverObject:%#010x\n", pDeviceObject->DriverObject));
}
KdPrint(("dump over\n"));
KdPrint(("------------------------------------------------------\n"));
}
//创建设备对象
NTSTATUS CreateDevice(PDRIVER_OBJECT pDriverObject, UNICODE_STRING &linkName, UNICODE_STRING &devName)
{
NTSTATUS status;
PDEVICE_OBJECT pDeviceObject;
PDeviceExtension pDevExt;
//创建设备对象
status = IoCreateDevice(pDriverObject, sizeof(DeviceExtension), &devName, FILE_DEVICE_UNKNOWN, , FALSE, &pDeviceObject);
if (!NT_SUCCESS(status))
{
return status;
}
//创建符号链接
status = IoCreateSymbolicLink(&linkName, &devName);
if (!NT_SUCCESS(status))
{
//删除设备对象
IoDeleteDevice(pDeviceObject);
return status;
}
//设置设备对象
pDeviceObject->Flags |= DO_BUFFERED_IO;
pDevExt = (PDeviceExtension)(pDeviceObject->DeviceExtension);
pDevExt->deviceName = devName;
pDevExt->symbolicName = linkName;
pDevExt->pDeviceObject = pDeviceObject;
return STATUS_SUCCESS;
}
//返回值不能为NTSTATUS,为VOID
VOID DriverUnLoad(PDRIVER_OBJECT pDriverObject)
{
KdPrint(("Leave\n"));
//删除设备对象
//删除符号链接
PDEVICE_OBJECT pcurDevice, pNextDevice;
pcurDevice = pDriverObject->DeviceObject;
while (NULL != pcurDevice)
{
PDeviceExtension pDevExt = (PDeviceExtension)(pcurDevice->DeviceExtension);
pNextDevice = pcurDevice->NextDevice;
IoDeleteSymbolicLink(&pDevExt->symbolicName);
IoDeleteDevice(pcurDevice);
pcurDevice = pNextDevice;
}
}
//IRP派遣函数
NTSTATUS DefaultDispatchRoutine(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
//显示IRP类型
KdPrint(("%d", pIrp->Type));
pDeviceObject;
return STATUS_SUCCESS;
}
extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegisterPath)
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING linkName,devName;
KdPrint(("Create\n"));
pRegisterPath;
//注册调用函数入口
pDriverObject->DriverUnload = DriverUnLoad;
pDriverObject->MajorFunction[IRP_MJ_CREATE] =
pDriverObject->MajorFunction[IRP_MJ_CLOSE] =
pDriverObject->MajorFunction[IRP_MJ_READ] =
pDriverObject->MajorFunction[IRP_MJ_WRITE] = DefaultDispatchRoutine;
//创建设备对象
RtlInitUnicodeString(&devName, L"\\Device\\C_1");
RtlInitUnicodeString(&linkName, L"\\??\\C_1");
status = CreateDevice(pDriverObject,linkName,devName);
if (!NT_SUCCESS(status))
{
return status;
} RtlInitUnicodeString(&devName, L"\\Device\\C_2");
RtlInitUnicodeString(&linkName, L"\\??\\C_2");
status = CreateDevice(pDriverObject, linkName, devName);
if (!NT_SUCCESS(status))
{
IoDeleteSymbolicLink(&linkName);
IoDeleteDevice(pDriverObject->DeviceObject);
return status;
}
dump(pDriverObject);
return status;
}

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

【原创】《windows驱动开发技术详解》第4章实验总结一的更多相关文章

  1. Windows驱动——读书笔记《Windows驱动开发技术详解》

    =================================版权声明================================= 版权声明:原创文章 谢绝转载  请通过右侧公告中的“联系邮 ...

  2. 【原创】《windows驱动开发技术详解》第4章实验总结二

    1 实验要求(WDM驱动)     2 编写过程   2.1 确立整体架构   2.1.1 入口函数——DriverEntry   (1)作用 设置pDriverObject结构体,注册AddDevi ...

  3. 《Windows驱动开发技术详解》之分层驱动程序

    分层驱动程序概念 分层的目的是将功能复杂的驱动程序分解成多个简单的驱动程序.一般来说,他们是指两个或两个 以上的驱动程序,它们分别创建设备对象,并且形成一个由高到低的设备对象栈.IRP请求一般会被传送 ...

  4. 《Windows驱动开发技术详解》之IRP的同步

    应用程序对设备的同步异步操作: 大部分IRP都是由应用程序的Win32 API函数发起的.这些Win32 API本身就支持同步和异步操作.例如,ReadFile.WriteFile和DeviceIoC ...

  5. 《Windows驱动开发技术详解》之Windows内存管理

    虚拟内存地址 Windows所有的程序(Ring0和Ring3层)可以操作的都是虚拟内存.有一部分单元会和物理内存对应起来,但并非一一对应,多个虚拟内存页可以映射同一个物理内存页.还有一部分单元会被映 ...

  6. 《Windows驱动开发技术详解》之HelloDDK

    编写如下代码:

  7. 《Windows驱动开发技术详解》之驱动程序调用驱动程序——通过设备指针调用其他驱动程序

    本节介绍“手动”构造各个IRP,然后将IRP传递到相应驱动程序的派遣函数里. 获得设备指针 每个内核中的句柄都会和一个内核对象的指针联系起来.ZwCreateFile内核函数可以通过设备名打开设备句柄 ...

  8. 《Windows驱动开发技术详解》之自定义StartIO

    自定义StartIO 系统定义的StartIO队列只能使用一个队列(DDK提供的StartIO内部只有一个队列),这个队列将所有的IRP进行处理化.例如,读.写操作都会混在一起进行串行处理.然而,有时 ...

  9. 《Windows驱动开发技术详解》之驱动程序的同步处理

    中断请求级 中断请求被分为软件中断和硬件中断两种,这些中断都映射成不同级别的中断请求级.每个中断请求都有各自的优先级别,正在运行的线程随时都可以被中断打断,进入到中断处理程序.优先级高的中断来临时,处 ...

随机推荐

  1. 小白的CTF学习之路4——内存

    明天要进行二模考试了,沉住气,加油,能过 内存是学C路上必不可少的一环,一定要非常认真的去学 内存的物理结构: ROM:只读内存——早期的手机 RAM:读写(数据断点既消) DRAM:经常更新 SRA ...

  2. Python的基本类型介绍和可变不可变

    Python的基本类型介绍 前言 做python有一段时间了,从工作开始就在不断地学习和积累.但是有时候用到一些技术点,甚至是基础知识的时候,总是会遗忘.所以,从今天开始,就在这里记录下来,不仅可以分 ...

  3. JavaScript基础视频教程总结(121-130章)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  4. mvc开发网站打开慢总结

    开始学习mvc开发网站的时候,看了传智博客的视频教程,其中学习了一个和牛逼的框架,开始激动的深入学习,学完后却发现其实那套框架太重并不适合一些中小型的网站开发,并且也使用导航属性关联外键,导致打开网站 ...

  5. 基于jmeter的性能测试平台(一)分布式jmeter搭建

    (1)概述 一台windows虚拟机作为controller,3台Linux虚拟机作为agent. 第一步是在所有虚拟机上安装JDK,版本最好是一样的,然后就是下载安装jmeter,网上资料很多这里不 ...

  6. Linux更新源汇总-18.9.7更新

    企业站 阿里云:https://opsx.alibaba.com/mirror 网易:http://mirrors.163.com/ 教育站 北京理工大学:http://mirror.bit.edu. ...

  7. JVM运行时数据区(二)

    4.本地方法栈 本地方法栈与虚拟机栈所发挥的作用是非常相似的,它们之间的区别不过是虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则为虚拟机使用到的Native方法服务. 与Java虚拟机栈一样本地 ...

  8. Spring Boot使用AOP实现REST接口简易灵活的安全认证

    我们继续上一篇文章的分析,本文将通过AOP的方式实现一个相对更加简易灵活的API安全认证服务. 我们先看实现,然后介绍和分析AOP基本原理和常用术语. 一.Authorized实现 1.定义注解 pa ...

  9. 背水一战 Windows 10 (94) - 选取器: 自定义文件打开选取器

    [源码下载] 背水一战 Windows 10 (94) - 选取器: 自定义文件打开选取器 作者:webabcd 介绍背水一战 Windows 10 之 选取器 自定义文件打开选取器 示例1.演示如何 ...

  10. Javascript高级编程学习笔记(60)—— 事件(4)事件类型

    事件类型 Web浏览器中可能发生的事件有许多种类型 不同类型的事件都有着自己独特的信息 在“DOM3级事件”规范中,规定了以下几类事件: UI事件    当用户与页面元素交互时触发 焦点事件    当 ...