`
dg239dg
  • 浏览: 21015 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

一个简单的NT驱动之驱动入口函数(DriverEntry)

 
阅读更多

一个简单的NT驱动之驱动入口函数(DriverEntry)
2011年12月16日
          选了本驱动开发方面的书《Windows驱动开发技术详解》,这本书类似于MFC方面孙鑫的《VC++深入详解》,看了一部分感觉还不错。
  在开始看这本书之前查了许多资料,是想看看自己的实际需求需要看些哪方面的书,但发现要学的技术太多了,汇编要学,操作系统要学。还是不管了,先找本书来看看再说。
  像学SDK时一样,照着书上的代码敲出了第一个驱动程序,称之为HelloDDK。
  在开发驱动程序之前,有些概念是需要了解的,但我了解得不多,反正把环境架设好,可以写驱动程序了。首先在微软的官方网站上下载了WDK,许多资料中都是让装DDK,其实WDK只是DDK的升级版本而已,性质跟SDK一样,属于开发包之列。
  这个驱动程序包含了三个函数:DriverEntry、HelloDDKUnload和HelloDDKDispatchRoutine。其中DriverEntry是驱动程序的入口函数,相当于C/C++程序的main函数,HelloDDKUnload函数是驱动卸载函数。而HelloDDKDispatchRuntine则是IRP的派遣函数,因为驱动程序主要是处理IO请求,而IO请求大多是在派遣函数中处理的。
  先来看看这个驱动程序的第一个函数:DriverEntry
  /****************************************************************
  * 函数名称:DriverEntry
  * 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象
  * 参数列表:
  pDriverObject:从I/O管理器中传来的驱动对象
  pRegistryPath:驱动程序在注册表中的路径
  * 返回值:返回初始化驱动状态
  ****************************************************************/
  #pragma INITCODE
  extern "C" NTSTATUS DriverEntry( IN PDRIVER_OBJECT pDriverObject,
  IN PUNICODE_STRING pRegistryPath )
  {
  NTSTATUS status;
  KdPrint( ( "Enter DriverEntry!\n" ) );
  //注册其它驱动调用函数入口
  pDriverObject->DriverUnload = ( PDRIVER_UNLOAD ) HelloDDKUnload;
  pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutine;
  pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutine;
  pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutine;
  pDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKDispatchRoutine;
  //创建驱动设备对象
  status = CreateDeivce( pDriverObject );
  KdPrint( ( "DriverEntry end!\n" ) );
  return status;
  }
  这个函数的第一句代码是一个#pragma预处理指令:
  #pragma INITCODE
  这段代码表明将此函数加入INIT内存区域。
  在函数头中的“extern "C"”是指定编译器的编译方式,若不加此修饰,编译器则会按C++的编译方式来编译,会导致编译错误。
  NTSTATUS是函数的返回状态,用来检测函数的状态是否正确,常用的NTSTATUS值有:
  #define STATUS_SUCCESS
  #define STATUS_BUFFER_OVERFLOW
  #define STATUS_UNSUCCESSFUL
  #define STATUS_NOT_IMPLEMENTED
  #define STATUS_ACCESS_VIOLATION
  #define STATUS_INVALID_HANDLE
  #define STATUS_INVALID_PARAMETER
  接着是函数参数中的IN修饰,该修饰是定义参数的类型,“IN”修饰表示是一个输入参数,“OUT”修饰表示是一个输出参数,“INOUT”修饰表示是一个输入输出参数。
  接下来就得了解了解驱动程序中的第一个结构体:PDRIVER_OBJECT,该结构体我在帮助文档里找了半天也没找到,最后在“wdm.h”中找到了其定义:
  typedef struct _DRIVER_OBJECT {
  CSHORT Type;
  CSHORT Size;
  PDEVICE_OBJECT DeviceObject;
  ULONG Flags;
  PVOID DriverStart;
  ULONG DriverSize;
  PVOID DriverSection;
  PDRIVER_EXTENSION DriverExtension;
  UNICODE_STRING DriverName;
  PUNICODE_STRING HardwareDatabase;
  PFAST_IO_DISPATCH FastIoDispatch;
  PDRIVER_INITIALIZE DriverInit;
  PDRIVER_STARTIO DriverStartIo;
  PDRIVER_UNLOAD DriverUnload;
  PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
  } DRIVER_OBJECT;
  typedef struct _DRIVER_OBJECT *PDRIVER_OBJECT;
  该结构体共有15个成员,这个结构体表示的是一个驱动对象,是驱动的一个实例,类似于用户模式下的线程句柄一类。该对象在DriverEntry函数中被始化,然后由内核中的I/O管理器来加载,确切的加载函数是IoCreateDevice。
  下面要说说该结构体中的几个重要成员:
  DeviceObject:这是一个设备对象的结构体。一个驱动程序会创建多个设备对象,每个设备对象都有指向下一个设备对象的指针,最后一个设备象的指针为空。此处的DeviceObject指向驱动程序的第一个设备对象,
  DriverName:驱动名称。其数据类型为UNICODE_STRING,该字符串一般为“\\driver\\[驱动名称]”,UNICODE_STRING字符串的赋值用RtlInitUnicodeString函数。
  DriverUnload:指定驱动卸载时使用的回调函数地址。
  MajorFunction:该成员是一个PDRIVER_DISPATCH结构体组数指针,其定义如下:
  __drv_functionClass(DRIVER_DISPATCH)
  __drv_requiresIRQL(PASSIVE_LEVEL)
  __drv_sameIRQL
  typedef
  NTSTATUS
  DRIVER_DISPATCH (
  __in struct _DEVICE_OBJECT *DeviceObject,
  __inout struct _IRP *Irp
  );
  typedef DRIVER_DISPATCH *PDRIVER_DISPATCH;
  每个指针指向一个函数,这个函数就是处理IRP的派遣函数。
  FastIoDispatch:文件驱动中用到的派遣函数。
  派遣函数相当于WIN32子系统下的事件响应函数,驱动程序的主要功能是负责处理IO请求,而绝大多数的IO请求是在派遣函数中处理的。关于IRP派遣函数的相关解释另作笔记。
  在PDRIVER_OBJECT中有一个PDEVICE_OBJECT成员,下面再来说说这个结构体,其定义在“wdm.h”中。该结构体保存的是设备对象指针链表,其成员包含了当前设备对象指针和下一个设备对象指针。在卸载驱动时要遍历驱动程序的所有设备对象,并用IoDeleteDevice来删除所有设备对象。
  好了,再来看看DriverEntry的函数体,在对以上的几个概念作了了解后,函数体的作用就容易理解了。函数体只有两个功能,一是初始化DRIVER_OBJECT结构体,二是创建设备对象。
  糊里糊涂的写完了这篇笔记,没想一个只有十来行的驱动函数涉及的内容居然如此之多。虽然还是云里雾里的,但对驱动对象PDRIVER_OBJECT还是有了一点了解,在下一篇笔记中再来好好研究研究CreateDevice函数。
  在敲这第一个驱动程序的代码时,老把Driver和Device敲错,到不是不知道这两个单词的意思,只是不知道在哪些地方该用驱动对象(DRIVER_OBJET),哪些地方用设备对象(DEVICE_OBJECT)。
分享到:
评论

相关推荐

    驱动编程+驱动逆向+驱动保护

    驱动入口函数DriverEntry 入口函数参数DriverObject和RegistryPath B、书写SOURCES文件 C、书写makefile文件 D、用DDK-Build环境编译 1.3.2为DDK_HelloWorld添加卸载例程-10课 A、输出调试信息-KdPrint B、...

    嵌入式 深入浅出学习驱动开发

    驱动程序同普通的 EXE,DLL一样,都属亍 PE文件,而且都有一个入口函数。但 EXE 中,入口函数是 main()/WinMain()和 Unicode的 wmain()/wWinmain(),DLL的入口函 数则可有可无,它是 DllMain()。驱动程序也有入口...

    windows驱动开发技术详解-part2

     4.2.1 驱动加载过程与驱动入口函数(DriverEntry)  4.2.2 创建设备对象  4.2.3 DriverUnload例程  4.2.4 用WinObj观察驱动对象和设备对象  4.2.5 用DeviceTree观察驱动对象和设备对象  4.3 WDM式驱动的...

    Windows驱动开发技术详解的光盘-part1

     4.2.1 驱动加载过程与驱动入口函数(DriverEntry)  4.2.2 创建设备对象  4.2.3 DriverUnload例程  4.2.4 用WinObj观察驱动对象和设备对象  4.2.5 用DeviceTree观察驱动对象和设备对象  4.3 WDM式驱动的...

    win2000驱动程序设计指南

    测试驱动程序 第一部分 一般内核模式 第1章Windows 2000和WDM驱动程序 第2章 分层的I/O、IRP和I/O对象 第3章 系统定义的对象和对驱动程序的支持 第4章 驱动程序基本结构 第5章DriverEntry 和 ...

    Windows内核安全驱动开发(随书光盘)

    9.3.2 Ramdisk驱动的入口函数 145 9.4 EvtDriverDeviceAdd函数 146 9.4.1 EvtDriverDeviceAdd的定义 146 9.4.2 局部变量的声明 146 9.4.3 磁盘设备的创建 147 9.4.4 如何处理发往设备的请求 148 9.4.5 用户...

    网络驱动程序设计指南

    3.1 NDIS微端口驱动程序入口函数 47 3.1.1 初始化包裹 47 3.1.2 注册微端口 48 3.1.2.1 指定NDIS版本号 48 3.1.2.2 注册MiniportXxx函数 48 3.1.2.3 为中断支持的注册处理程序 50 3.1.2.4 为无连接微端口选择一个...

    Windows内核安全与驱动开发光盘源码

    9.3.2 Ramdisk驱动的入口函数 145 9.4 EvtDriverDeviceAdd函数 146 9.4.1 EvtDriverDeviceAdd的定义 146 9.4.2 局部变量的声明 146 9.4.3 磁盘设备的创建 147 9.4.4 如何处理发往设备的请求 148 9.4.5 用户...

    寒江独钓-Windows内核安全编程(高清完整版).part1

    4.7.5 驱动入口和卸载的实现 95 4.8 直接用端口操作键盘 96 4.8.1 读取键盘数据和命令端口 96 4.8.2 p2cUserFilter的最终实现 97 本章的示例代码 98 练习题 99 第5章 磁盘的虚拟 100 5.1 虚拟的磁盘 101 5.2 一个...

    寒江独钓-Windows内核安全编程(高清完整版).part7

    4.7.5 驱动入口和卸载的实现 95 4.8 直接用端口操作键盘 96 4.8.1 读取键盘数据和命令端口 96 4.8.2 p2cUserFilter的最终实现 97 本章的示例代码 98 练习题 99 第5章 磁盘的虚拟 100 5.1 虚拟的磁盘 101 5.2 一个...

    寒江独钓-Windows内核安全编程(高清完整版).part4

    4.7.5 驱动入口和卸载的实现 95 4.8 直接用端口操作键盘 96 4.8.1 读取键盘数据和命令端口 96 4.8.2 p2cUserFilter的最终实现 97 本章的示例代码 98 练习题 99 第5章 磁盘的虚拟 100 5.1 虚拟的磁盘 101 5.2 一个...

    寒江独钓-Windows内核安全编程(高清完整版).part6

    4.7.5 驱动入口和卸载的实现 95 4.8 直接用端口操作键盘 96 4.8.1 读取键盘数据和命令端口 96 4.8.2 p2cUserFilter的最终实现 97 本章的示例代码 98 练习题 99 第5章 磁盘的虚拟 100 5.1 虚拟的磁盘 101 5.2 一个...

    寒江独钓-Windows内核安全编程(高清完整版).part5

    4.7.5 驱动入口和卸载的实现 95 4.8 直接用端口操作键盘 96 4.8.1 读取键盘数据和命令端口 96 4.8.2 p2cUserFilter的最终实现 97 本章的示例代码 98 练习题 99 第5章 磁盘的虚拟 100 5.1 虚拟的磁盘 101 5.2 一个...

    寒江独钓-Windows内核安全编程(高清完整版).part2

    4.7.5 驱动入口和卸载的实现 95 4.8 直接用端口操作键盘 96 4.8.1 读取键盘数据和命令端口 96 4.8.2 p2cUserFilter的最终实现 97 本章的示例代码 98 练习题 99 第5章 磁盘的虚拟 100 5.1 虚拟的磁盘 101 5.2 一个...

    寒江独钓-Windows内核安全编程(高清完整版).part3

    4.7.5 驱动入口和卸载的实现 95 4.8 直接用端口操作键盘 96 4.8.1 读取键盘数据和命令端口 96 4.8.2 p2cUserFilter的最终实现 97 本章的示例代码 98 练习题 99 第5章 磁盘的虚拟 100 5.1 虚拟的磁盘 101 5.2 一个...

    驱动程序设计基础专题-filedisk源码分析

    可以不用重起机子的方法,找一个动载加载驱动工具:DriverMonitor不错了。然后在“开始菜单”-> "运行"输入 "net start filedisk" 出现:“ 请求的服务已经启动”。这个必须得成功才行哦。 接下来注意点。cmd后 ...

    虚拟还原功能的源代码

    2 FileDiskCreateDevice:调用IoCreateDevice创建设备,KeInitializeEvent初始化事件对象,PsCreateSystemThread创建内核线程,入口函数是FileDiskThread,传入的函数参数为IoCreateDevice返回的设备对象。...

    基于TDI 的 TCP数据传输

    驱动装载主入口函数 NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath); 驱动卸载函数 VOID D1603Unload(PDRIVER_OBJECT DriverObject); 默认IRP回调函数 NTSTATUS D1603Dispatch...

Global site tag (gtag.js) - Google Analytics