Windows驱动开发(一)第一个驱动程序

2023-09-14 00:49:55

首先我们需要了解,在操作系统中,是分两种权限的,一种是内核态,我们也称为0环,一种是用户态,称之为3环。而在我们的电脑中,驱动程序是运行在内核态的,这意味着和操作系统内核是在同一权限的,而普通的应用程序的权限是最低的。高权限谁不想拥有呢,因此驱动程序是很有必要了解与学习的。比如我们熟知的防病毒软件,游戏保护等,现在都在利用内核驱动技术来保护自己的数据。

windows提供了好几种驱动框架模型,这里我们采用WDM模型,这是自winodws 2000来提供给开发者的一种框架,我们用来开发NT驱动。下面我们介绍驱动程序该如何编写,其实驱动程序和普通的应用程序C语言没什么特别大的区别,在C语言中我们需要一个main函数作为入口,那么在驱动程序中DriverEntry就是主函数入口,下面我们来实现一个hello,world版本的驱动程序,代码如下:

#include<Ntddk.h>
void Unload(IN PDRIVER_OBJECT DriverObject)
{
	UNREFERENCED_PARAMETER(DriverObject);
	DbgPrint("Unload\n");

	}

}

NTSTATUS DriverEntry(
	IN PDRIVER_OBJECT DriverObject,
	IN PUNICODE_STRING RegistryPathName)
{
	UNREFERENCED_PARAMETER(RegistryPathName);
	DbgPrint("Hello Driver!!\n");
    DriverObject->DriverUnload = Unload;
    return  STATUS_SUCCESS;

}

我第一次接触这段代码的时候非常陌生和惶恐,竟然没有一句看懂的,但是只要我们耐下性子来研究这个东西,没什么难的。我们再写一个C语言版本的helo,world来对比研究:

#include<stdio.h>

int main(){

printf("hello,world!");
return 0;
}

 在编写一个程序时我们需要一个主函数,而且需要一个返回值来表示程序的结束。在驱动中返回值一般都是NTSTATUS,这是一种状态码,成功的时候需要返回STATUS_SUCCESS。相当于C语言中的return 0。接着看驱动程序主函数中有两个参数,第一个是一个驱动对象。在内核中,系统管理的都是对象。一些重要的数据结构都是以对象为主体来操控的。我们写的是驱动程序,自然需要一个驱动对象。PDRIVER_OBJECT是一个指针,指向一个驱动对象。这个驱动对象就是对应着我们写的这个驱动程序。是系统帮我们规划好的模板,按照这个模板写程序就行了。因此我们可以看看这个驱动对象的样子:

typedef struct _DRIVER_OBJECT {
    CSHORT Type;
    CSHORT Size;

    //
    // The following links all of the devices created by a single driver
    // together on a list, and the Flags word provides an extensible flag
    // location for driver objects.
    //

    PDEVICE_OBJECT DeviceObject;
    ULONG Flags;

    //
    // The following section describes where the driver is loaded.  The count
    // field is used to count the number of times the driver has had its
    // registered reinitialization routine invoked.
    //

    PVOID DriverStart;
    ULONG DriverSize;
    PVOID DriverSection;
    PDRIVER_EXTENSION DriverExtension;

    //
    // The driver name field is used by the error log thread
    // determine the name of the driver that an I/O request is/was bound.
    //

    UNICODE_STRING DriverName;

    //
    // The following section is for registry support.  This is a pointer
    // to the path to the hardware information in the registry
    //

    PUNICODE_STRING HardwareDatabase;

    //
    // The following section contains the optional pointer to an array of
    // alternate entry points to a driver for "fast I/O" support.  Fast I/O
    // is performed by invoking the driver routine directly with separate
    // parameters, rather than using the standard IRP call mechanism.  Note
    // that these functions may only be used for synchronous I/O, and when
    // the file is cached.
    //

    PFAST_IO_DISPATCH FastIoDispatch;

    //
    // The following section describes the entry points to this particular
    // driver.  Note that the major function dispatch table must be the last
    // field in the object so that it remains extensible.
    //

    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; 

        这是WDK里面跟进去看到的驱动对象。学过C语言的一定看得懂,其实就是个结构体。虽然在winodws内核中是用纯C写的,但是却用到了面向对象的思想。只用C语言的结构体,一样可以实现面向对象编程。这个对象是什么时候生成的呢?这也是我在学习驱动时候的好奇。后来我想明白了,在我们想要加载我们的驱动程序的时候,操作系统其实为我们做好了初始化,为我们创建一个驱动对象。如果创建成功将把这个驱动对象的地址返回给我们,因此我们就能拿着这个地址对这个驱动对象做很多事了。接下来介绍第二个参数RegistryPathName。这个参数指的是在注册表中的位置。返回给我们的也是一个指针,告诉我们它在注册表何处。接着我们用内核提供的"printf"打印一句话--Hello Driver!!。到这里和C语言相同的地方我们就讲的差不多了。下面还有一些区别于C语言的东西。

        现在我们知道驱动程序加载是在内核空间的。内核空间不像用户空间那么随意,有些东西想关就关,想开就开。稍不留神可能就造成电脑蓝屏。因此我们可能还需要提供一个卸载的功能,否则这个驱动将无法卸载。但是其实这个也不是必要的。很多商用的软件并不想别人把它关掉,自然不会提供这么一个卸载功能。这就像为啥有些杀软删不掉的原因(懂得都懂)。但是我们在做测试过程中,还是要提供这么一个卸载函数。这个函数是我们自己写的。驱动对象中会记录这个回调函数。可以参考下上面驱动对象中有一个成员叫DriverUnload,这就是指向我们提供的卸载函数的指针。因此通过驱动对象指针能访问到它。将它设置为我们提供的卸载函数。在我们提供的卸载函数中,我们目前也只提供打印一句话的功能。卸载驱动的过程是操作系统为我们隐式做的。当系统检测到驱动对象中有这么个卸载函数,将去执行我们提供的回调函数。并把我们的驱动从内核中卸载。大致了解这个过程就OK了。因此,到目前为止,我们的第一个驱动程序就完成了。我们在XP下试验一下:

我们在测试工具中看到了Hello Driver,后面两句不用管那是后续实现的功能。我们再看卸载后的状态:

我们看到停止驱动后,系统会调用我们提供的卸载回调函数,并打印了一句Unload。证明我们的驱动是没问题的。

更多推荐

1.1 安装配置CentOS

文章目录零、学习目标一、导入新课二、新课讲解(一)安装VMWareWorkstation1、获取安装程序2、进入安装向导3、按提示完成安装(二)虚拟网络编辑器1、启动虚拟网络编辑器2、选择VMnet8虚拟网3、更改网络配置4、查看DHCP设置5、查看NAT设置(三)在VMWare上安装CentOS71、启动新建虚拟机向

加密算法、哈希算法及其区别+国密简介

现代加密算法是信息安全领域中常用的算法,用于保护数据的机密性和完整性。以下是一些常用的现代加密算法:加密算法(EncryptionAlgorithm)目标:加密算法的主要目标是保密性(Confidentiality),它用于将明文数据转换为密文数据,以确保只有授权的用户或实体可以解密和访问数据。加密算法的目标是隐藏信息

跨模态检索论文阅读:(PTP)Position-guided Text Prompt for Vision-Language Pre-training

(PTP)Position-guidedTextPromptforVision-LanguagePre-training视觉语言预训练的位置引导文本提示摘要视觉语言预训练(VLP)已经显示出将图像和文本对统一起来的能力,促进了各种跨模态的学习任务。然而,我们注意到,VLP模型往往缺乏视觉基础/定位能力,这对许多下游任务

【深度学习】 Python 和 NumPy 系列教程(廿四):Matplotlib详解:2、3d绘图类型(10)3D箱线图(3D Box Plot)

目录一、前言二、实验环境三、Matplotlib详解1、2d绘图类型2、3d绘图类型0.设置中文字体1.3D线框图(3DLinePlot)2.3D散点图(3DScatterPlot)3.3D条形图(3DBarPlot)4.3D曲面图(3DSurfacePlot)5.3D等高线图(3DContourPlot)6.3D向量

ICCV 2023 | 沉浸式体验3D室内设计装修,基于三维布局可控生成最新技术

文章链接:https://arxiv.org/abs/2307.09621360°场景布局可控合成(360-degreeImageSynthesis)目前已成为三维计算机视觉领域一个非常有趣的研究方向,在虚拟三维空间中沉浸式的调整和摆放场景对象,可以为用户带来身临其境的感觉,非常适合应用在3D家居模拟装饰领域。本文提出

低代码提案管理应用:发挥员工“金点子”,小提案能有大作用

提案也称合理化建议,是制造企业实施精益管理的重要抓手。制造企业常常采用改善提案制度,引导和鼓励公司全体员工积极主动地提出任何能够改善企业经营质量、提高管理能力的建议。精益管理在日本丰田汽车公司发扬光大,提案管理也是如此。丰田的员工改善提案制度有超过50年的历史,据统计,1986年丰田公司合理化建议数为2,648,710

【SpringMVC】JSR303与拦截器的使用

文章目录一、JSR3031.1JSR303是什么1.2JSR303的好处包括1.3常用注解1.4实例1.4.1导入JSR303依赖1.4.2规则配置1.4.3编写校验方法1.4.4编写前端二、拦截器2.1拦截器是什么2.2拦截器与过滤器的区别2.3.应用场景2.4快速入门2.5.拦截器链2.6登录拦截权限案例2.6.1

Ajax基础笔记

Ajax(AsynchronousJavaScriptandXML)是一种用于在网页上实现异步通信的技术。它使得网页能够在不重新加载整个页面的情况下与服务器进行数据交换,实现了网页的动态更新,提升了用户体验。一、Ajax的工作原理使用JavaScript创建XMLHttpRequest对象,然后使用该对象向服务器发送H

软件测试/测试开发丨利用ChatGPT自动生成测试用例思维导图

点此获取更多相关资料简介思维导图是一种用图形方式表示思维和概念之间关系的工具:有些公司会使用思维导图编写测试用例,这样做的优点是:1.可视化和结构化。2.易于理解,提高效率。而ChatGPT是无法直接生成xmind格式的文件的,但是依然可以通过“曲线救国”的方式去编写思维导图格式的测试用例。实践演练那么如何让ChatG

线程安全问题的原因及解决方案

要想知道线程安全问题的原因及解决方案,首先得知道什么是线程安全,想给出一个线程安全的确切定义是复杂的,但我们可以这样认为:如果多线程环境下代码运行的结果是符合我们预期的,即在单线程环境应该的结果,则说这个程序是线程安全的。例如:使用两个线程分别对同一个变量进行修改,得出的结果与使用一个线程对这个变量进行修改的结果不同,

【推荐】SpringMVC与JSON数据返回及异常处理机制的使用

🎬艳艳耶✌️:个人主页🔥个人专栏:《【推荐】Spring与Mybatis集成整合》⛺️生活的理想,为了不断更新自己!1.JSON在SpringMVC中,JSON数据返回通常是通过使用`@ResponseBody`注解将Java对象转换为JSON格式,并直接发送给客户端。该注解可以用于Controller中的方法,用

热文推荐