首页 > 系统相关 >Windows内核开发-[2]、创建第一个驱动程序

Windows内核开发-[2]、创建第一个驱动程序

时间:2024-01-26 22:46:28浏览次数:37  
标签:DriverObject 函数 DriverUnload Windows DriverEntry 内核 驱动 驱动程序

使用Visual Studio 2022创建一个Empty WDM Driver工程

 

 工程创建后,添加一个MyFirstDriver.cpp文件,输入以下内容

 1 #include<ntddk.h>
 2 
 3 VOID DriverUnload(PDRIVER_OBJECT DriverObject)
 4 {
 5     if (DriverObject != NULL)
 6     {
 7         DbgPrint("Driver Unload...Driver Object Address: %p\n", DriverObject);
 8     }
 9 
10     return;
11 }
12 
13 extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
14 {
15     DbgPrint("Hello World\n");
16 
17     if (RegistryPath != NULL)
18     {
19         DbgPrint("Driver RegistryPath: %wZ\n", RegistryPath);
20     }
21 
22     if (DriverObject != NULL)
23     {
24         DbgPrint("Driver Object Address: %p\n", DriverObject);
25         DriverObject->DriverUnload = DriverUnload;
26     }
27 
28     return STATUS_SUCCESS;
29 }

这里需要注意的是,可以直接创建后缀为.c的文件,如果后缀是.cpp,需要在DriverEntry前增加extern "C",否则会报下面的错

DriverEntry函数必须具有C语言的链接方式,但是C++编译默认的方式不是C的。 

下面详细介绍代码中的内容


ntddk.h

内核开发所需要的头文件

 

DriverEntry

和控制台的Main函数一样,驱动的入口函数就是DriverEntry。这个函数会被系统线程在IRQLPASSIVE_LEVEL (0)上调用(IRQL会在后面详细讨论)。

 

DriverEntry函数的原型如下:

1 NTSTATUS DriverEntry(PDRIVER_OBECT DriverObject, PUNICOOE_STRING RegistryPath);

第一个参数为DriverObject,表示一个驱动对象的指针,可以简单认为,一个驱动文件(sys)运行之后,操作系统在内存中为该驱动分配了一个类型为DRIVER_OBJECT的数据结构,用于记录该驱动的详细信息
第二个参数RegistryPath,是一个类型为UNICODE_STRING的指针,表示当前驱动所对应的注册表位置。UNICODE_STRING是内核中表示字符串的结构体,对应定义如下:

typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWCH Buffer; //PWCH -> wchar_t* 不要求以'\0'结束 
} UNICODE_STRING

因为内核驱动是作为Windows系统服务( Service)存在的,Windows系统有众多服务,如果从服务运行的环境来分区,服务分为用户态服务,以及内核态服务,但无论何种服务,都统称为“服务( Service)”,不同服务通过服务的名字来识别。一个驱动SYS文件需要运行(加载到内核中),首先需要把这个驱动文件注册(创建)成一个服务(第三方服务),注册成功后,系统会把该服务信息写入到注册表HKEY_LOCAL_MACHINE \ SYSTEM \CurrentControlSet lServices下,以服务的名字作为一个注册表的键名。

如本示例中的驱动注册成功后可以在注册表中看到如下键值

 

返回值NTSTATUS,NTSTATUS实际是一个LONG类型,定义如下:

1 typedef LONG NTSTATUS;

DriverEntry返回STATUS_SUCCESS表示成功,返回其他值表示失败。

STATUS_SUCCESS定义如下:

1 #define STATUS_SUCCESS                   ((NTSTATUS)0x00000000L)    // ntsubauth

简单来说,内核驱动作为Windows服务运行,在执行具体代码前,驱动SYS文件首先会被映射到内核地址空间,作为内核的一个驱动模块(MODULE),接着系统对这个驱动模块执行导入表初始化、修正重定位表中对应的数据偏移等操作,最后系统会调用该驱动模块的DriverEntry 入口函数,如果这个入口函数返回STATUS_SUCCESS,系统认为这个驱动初始化成功;如果这个入口函数返回除STATUS_SUCCESS以外的其他值,系统认为驱动初始化失败,系统执行一系列的清理工作,并把驱动模块从内核空间中移除,从用户态角度看,就是服务启动失败。

 

DriverUnload

有时候驱动程序需要卸载。在卸载驱动时(关闭服务),DriverObject->DriverUnload函数会被调用,以便执行一些清理操作。需要注意的是,如果未在DriverUnload中执行清理工作,会产生泄漏,在下一次重启之前,内核无法清除这些泄漏。(这一点不像用户层编程,在进程退出后,资源会释放,但是内核层不会自己释放。)

 

DriverUnload函数非常重要,但DriverUnload函数是可选的,开发者可以不提供DriverUnload函数,这样做的结果是该驱动不支持停止,也就是说,只要开发者不提供DriverUnload函数,这个驱动对应的服务一旦启动后,再也无法停止。该特性被很多安全软件利用,刻意不提供DriverUnload函数,避免驱动被恶意停止。

 

需要注意的是:

驱动初始化失败不会触发DriverUnload函数的调用,DriverUnload只有在驱动服务成功启动(初始化)后,被要求停止时才会触发。

 

DbgPrint函数

DbgPrint函数是WDK提供的API,类似用户层的OutputDebugString函数。DbgPrint与C语言的printf使用基本一样。
与DbgPrint函数功能类似的是KdPrint函数,但KdPrint函数只是针对DEBUG版本的驱动有效。

%wZ用来输出以非'\0'结束的字符串

%ws用来输出以'\0'结束的字符串

在上述的示例代码中,对DriverObject的地址和RegistyPath进行了输出。

 

编译

直接在Visual Studio中编译即可,编译成功后可以在输出目录得到一个MyFirstDriver.sys文件。

 

加载并运行驱动

按照Windows系统要求,驱动文件必须经过微软的数字签名后,才可以运行在64位系统上。像平常我们在测试阶段是不会为驱动签名的,可以通过下面两种方式绕过系统的验证。

1、启用调试模式

2、禁用驱动程序强制签名

这两种方式都是通过启动设置里的设置来完成的。下次开机时会失效,需要重新设置。

 

这里以禁用驱动程序强制签名为例

打开开始菜单,在选择重启时,按住shift键

 

然后就会出现Windows高级启动菜单,依次选择 疑难解答->启动设置->按数字键7选择禁用驱动程序强制签名

 

 以管理员运行cmd,执行如下命令,创建一个服务(driverpath需要替换成上面工程生成的.sys文件路径)

1 sc create MyFirstDriver binPath= "driverpath" type= kernel

 

创建成功后,用管理员权限运行DebugView.exe(SysInternals工具包里的一个工具),DebugView工具可以查看DbgPrint的输出内容。

在菜单中钩选相应选项,如下图所示

 

此时,我们可以运行驱动(启动服务)

在控制台输入

1 sc start MyFirstDriver

可以在DebugView看到DriverEntry函数里的输出内容

 

我们再卸载驱动(停止服务)

在控制台输入

1 sc stop MyFirstDriver

 

可以在DebugView看到DriverUnload函数的输出内容

 

至此,一个简单的驱动程序已经编写完成了,目前我们暂时先不考虑内核开发的任何理论支撑,仅仅写一个HelloWorld一样的程序。

 

示例代码 

 

题外话:

因为以前也没接触过内核开发,在书上看到使用KeBugCheckEx()函数可以主动引发蓝屏,试了一下,确实可以,还挺好玩的。

1 KeBugCheckEx(INVALID_DATA_ACCESS_TRAP, NULL, NULL, NULL, NULL); 

 

 

参考资料:

Windows内核开发示例代码

https://github.com/Microsoft/Windows-driver-samples

驱动程序概述

https://learn.microsoft.com/zh-cn/windows-hardware/drivers/device-and-driver-technologies

标签:DriverObject,函数,DriverUnload,Windows,DriverEntry,内核,驱动,驱动程序
From: https://www.cnblogs.com/zhaotianff/p/17942863

相关文章

  • Windows内核开发-[3]、驱动调试方法
    单步调试驱动驱动的调试不能直接在本机上进行,而是要放在虚拟机(或其它设备)中。这是因为在内核模式下,一个断点的触发将会停下整个系统而不只是单个进程。在前面的文章里,使用了DbgPrint函数来进行日志的输出,但这种方法不能进行单步调试。下面介绍两种调试方法。 基于VisualStud......
  • ZSH!在 Windows 上使用 WSL+ZSH
    ZSH!在Windows上使用WSL+ZSH1.安装WSL关于如何安装WSL这里就不介绍了,大家可以去找找相关的教程,很多。最直接的就是去微软官方:https://learn.microsoft.com/en-us/windows/wsl/install最简单的方法是从MicrosoftStore安装Ubuntu2.ubuntu在开始菜单中搜索Ubuntu图标并打开终端......
  • .NET Core 6.0 Windows部署
    varoptions=newWebApplicationOptions{Args=args,//这是因为从Windows中调用GetCurrentDirectory会返回:C:\WINDOWS\system32//需要注意使用了WindowsService部署,就不能使用Console类,否则会报错ContentRootPath=WindowsServiceHelpers.IsWindowsServi......
  • 记windows自定义bat脚本自启动
    自定义Windows启动脚本简化版在本指南中,我们将使用一个简化的批处理文件(.bat)来演示如何创建自定义的Windows启动脚本。以下是一个基本的模板,您只需根据需要在:begin部分添加您的代码。 @echooffif"%1"=="h"gotobeginrem获取脚本路径set"scriptPath=%~dp0"......
  • windows使用VMware安装macOS
    1.准备工作笔记本型号:dellG33579i5-8300H款VMware:15.5(VMwareWorkstation的安装流程省略...)macOS:10.15.1Catalina(来自:https://www.bilibili.com/video/BV1zK4y1b7hU/?spm_id_from=333.999.0.0&vd_source=619d0f384650adc67c5cff8a3767b490)unlocker427(来自github大佬......
  • windows的bitlocker解密
    概念WindowsBitLocker驱动器加密通过加密Windows操作系统卷上存储的所有数据可以更好地保护计算机中的数据。BitLocker使用TPM(受信任的平台模块)帮助保护Windows操作系统和用户数据,并帮助确保计算机即使在无人参与、丢失或被盗的情况下也不会被篡改。 取证方法(目前想到的)想要......
  • Windows快捷键重启的几种方式
    Ctrl+Alt+Delete:按下这个组合键后,您可以选择重新启动电脑或其他选项Ctrl+Shift+Esc:直接打开任务管理器,然后在任务管理器中选择“文件”>“运行新任务”,输入"shutdown/r"执行重新启动命令。Win+X,然后选择“关机或注销”菜单中的“重新启动”。请注意,不同的操作系统......
  • windows下的mklink命令
    mklink命令用于创建符号连接,有三个选项,/D、/J、/H。/D创建目录符号链接。默认为文件符号链接。/H创建硬链接而非符号链接。/J创建目录联接先使用三个参数分别创建文件、文件夹试试思路:创建一个分本和目录,然后分别使用D、J、H三个参数来创建目录链接和......
  • 关闭windows的系统还原
    先删除系统还原保存的还原点系统保护中,点配置,然后删除还原点,并关闭系统还原在组策略中禁用系统还原按Win+R键打开运行窗口,输入gpedit.msc并按Enter键打开组策略编辑器。在组策略中,依次打开:计算机配置\管理模板\系统\系统还原,然后在右侧窗口中,找到名为“关闭系统......
  • 在 Windows 中配置 WSL2 与 Debian 的全流程
    在Windows中配置WSL2与Debian的全流程ref:HowtoInstallWSL2onWindows10(Updated)-visitedon2024-01-09Microsoft-如何使用WSL在Windows上安装Linux-visitedon2024-01-09清华大学开源软件镜像站-Debian软件源-visitedon2024-01-09ArchWiki:F......