Windows 驱动开发 新手入门(四)

这篇具有很好参考价值的文章主要介绍了Windows 驱动开发 新手入门(四)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

引言

本系列所有文章
Windows 驱动开发 新手入门(一)
Windows 驱动开发 新手入门(二)
Windows 驱动开发 新手入门(三)
Windows 驱动开发 新手入门(四)

本篇文章介绍一下设备对象,这是写驱动过滤的基础,比如键盘,串口等等的过滤。

PDO

PDOPhsical Device Object的缩写,直译就是物理设备对象,一般来说,PDO就是在就是DeviceStack中最下层的设备对象。

获取设备对象

IoGetDeviceObjectPointer

IoGetDeviceObjectPointer 只能返回设备对象地址。

NTSTATUS IoGetDeviceObjectPointer(
  [in]  PUNICODE_STRING ObjectName,
  [in]  ACCESS_MASK     DesiredAccess,
  [out] PFILE_OBJECT    *FileObject,
  [out] PDEVICE_OBJECT  *DeviceObject
);
  • ObjectName 指向包含 Unicode 字符串的缓冲区的指针,该字符串是设备对象的名称。

  • DesiredAccess 指定表示所需访问的权限掩码值。 通常 ,DesiredAccess指定FILE_READ_DATA。 不经常指定FILE_WRITE_DATA或FILE_ALL_ACCESS访问权限。

  • FileObject 指向表示相应设备对象到用户模式代码的文件对象的指针(如果调用成功)。

  • DeviceObject 指向表示命名逻辑、虚拟或物理设备(如果调用成功)的设备对象的指针。

IoGetDeviceObjectPointer 小栗子

下面的栗子是打开串口3的设备。

PDEVICE_OBJECT OpenSeria3()
{
	PFILE_OBJECT pFileObject = NULL;
	PDEVICE_OBJECT pDeviceObject = NULL;
	UNICODE_STRING deviceNameStr;
	RtlInitUnicodeString(&deviceNameStr, L"\\Device\\Serial3");
	NTSTATUS status = IoGetDeviceObjectPointer(&deviceNameStr, FILE_ALL_ACCESS, &pFileObject, &pDeviceObject);
	if (status == STATUS_SUCCESS)
		ObDereferenceObject(pFileObject);//用不到file_object,所以先解除引用
	return pDeviceObject;
}

ObReferenceObjectByName

需要自己手动导入,ObReferenceObjectByName 能够返回任意对象地址,所以它同样可以返回设备对象。

//使用NTKERNELAPI宏
NTKERNELAPI NTSTATUS ObReferenceObjectByName(__in PUNICODE_STRING  ObjectName,
	__in ULONG  Attributes,
	__in_opt PACCESS_STATE  AccessState,
	__in_opt ACCESS_MASK  DesiredAccess,
	__in POBJECT_TYPE  ObjectType,
	__in KPROCESSOR_MODE  AccessMode,
	__inout_opt PVOID  ParseContext,
	__out PVOID* Object
);

ObReferenceObjectByName小栗子

这次我们获取键盘驱动对象

//直接声明即可,其实是存在的
extern POBJECT_TYPE IoDriverObjectType;
PDEVICE_OBJECT OpenKeyboard()
{
	
	PDRIVER_OBJECT pKbdDriverObject = NULL;
	UNICODE_STRING driverNameStr;
	RtlInitUnicodeString(&driverNameStr, L"\\Driver\\Kbdclass");// Kbdclass驱动名

	NTSTATUS status = ObReferenceObjectByName(&driverNameStr, OBJ_CASE_INSENSITIVE, NULL, 0, IoDriverObjectType, KernelMode, NULL, &pKbdDriverObject);
	if (status == STATUS_SUCCESS) {
		//调用ObReferenceObjectByName后,对象引用计数会+1,我们需要解引
		///不是说我们用不到它,是因为它本身就存在,是我们导致的引用计数增加了
		ObDereferenceObject(pKbdDriverObject);
	}
	
	return pKbdDriverObject->DeviceObject;
}

设备绑定

Windows系统为了方便开发者,无论在应用层还是内核层都实现了分层的设计,比如应用层的LSP,驱动开发中也同样,我们想实现过滤器,就要在设备的上层和下层之间,插入我们自己的虚拟设备,让我们在不影响正常数据的情况下,实现过滤。

IoAttachDevice

NTSTATUS IoAttachDevice(
  [in]  PDEVICE_OBJECT  SourceDevice,
  [in]  PUNICODE_STRING TargetDevice,
  [out] PDEVICE_OBJECT  *AttachedDevice
);
  • SourceDevice源设备(也就是我们生成的虚拟设备,用来过滤)
  • TargetDevice目标设备,也就是我们要绑定的设备,你也可以理解为附加(注意这是一个UNICODE_STRING指针,是设备名,而非设备对象)
  • AttachedDevice是用来返回的2级指针,绑定成功之后,返回目标设备栈最顶层设备

IoAttachDeviceToDeviceStackSafe

这个和IoAttachDevice的区别是参数TargetDevice也是设备对象了。

NTSTATUS IoAttachDeviceToDeviceStackSafe(
  [in]  PDEVICE_OBJECT SourceDevice,
  [in]  PDEVICE_OBJECT TargetDevice,
  [out] PDEVICE_OBJECT *AttachedToDeviceObject
);

这个函数最低受支持的客户端 Windows 2000 Service Pack 4 (SP4) 和 Windows XP 及更高版本。

IoAttachDeviceToDeviceStackSafeIoAttachDevice的区别在于:在获取到 I/O 系统数据库锁时更新此字段
由于它获取到了锁, 因此,如果SourceDevice对象在其AttachedToDeviceObject字段更新之前收到一个IRP,IoAttachDeviceToDeviceStackSafe可避免可能发生的竞争状况。

IoAttachDeviceToDeviceStack

IoAttachDeviceToDeviceStackSafe一样,只是这个我并不推荐使用,他并没有获取锁。

PDEVICE_OBJECT IoAttachDeviceToDeviceStack(
  [in] PDEVICE_OBJECT SourceDevice,
  [in] PDEVICE_OBJECT TargetDevice
);

获取绑定的设备

绑定之后的设备就是在设备栈中的最顶层,所以下面这个API就是获取最顶层的设备

IoGetAttachedDevice

文件头ntifs.h,如果仅引入了ntddk.h,可以使用IoGetAttachedDeviceReference代替,它会多加一次引用计数。

PDEVICE_OBJECT IoGetAttachedDevice(
  [in] PDEVICE_OBJECT DeviceObject
);
  • DeviceObject 指向要返回其 最顶层附加设备的设备对象的指针。

看一下下面的代码回有直观的理解

void test(){
		ccpAttachDevice(driver, com_ob, &s_fltobj[i], &s_nextobj[i]);
		PDEVICE_OBJECT top = IoGetAttachedDeviceReference(s_nextobj[i]);
		
		DbgPrint("pTarget %p pFilter %p   pAttached %p top %p\n", com_ob, s_fltobj[i], s_nextobj[i], top);
		ObDereferenceObject(top);
}
pTarget FFFFE28A63151A60 pFilter FFFFE28A652AFE10   pAttached FFFFE28A63151A60 top FFFFE28A652AFE10

设备栈处理

IoSkipCurrentIrpStackLocation

void IoSkipCurrentIrpStackLocation(
  [in, out] PIRP Irp
);

驱动程序向下一个较低的驱动程序发送 IRP 时,如果我们不打算提供IoCompletion例程(也就是我们不处理,直接交给我们绑定之前的设备处理),驱动程序可以调用IoSkipCurrentIrpStackLocation 。如果在调用IoCallDriver之前调用IoSkipCurrentIrpStackLocation,则下一个较低的驱动程序会收到与我们驱动程序相同的IO_STACK_LOCATION

如果打算为IRP提供IoCompletion例程,应调用IoCopyCurrentIrpStackLocationToNext而不是IoSkipCurrentIrpStackLocation
如果驱动程序已挂起 IRP,则驱动程序不应将 IRP 传递给下一个较低驱动程序之前调用IoSkipCurrentIrpStackLocation 。如果驱动程序在将挂起的 IRP 传递给下一个较低的驱动程序之前调用IoSkipCurrentIrpStackLocation ,则仍会在下一个驱动程序的 I/O 堆栈位置的控制成员中设置 SL_PENDING_RETURNED 标志。因为下一个驱动程序拥有该堆栈位置并可能修改它,它可能会清除挂起标志。这种情况可能会导致操作系统发出错误检查或 IRP 的处理永远不会完成。
相反,已挂起 IRP 的驱动程序应在调用IoCallDriver之前调用IoCopyCurrentIrpStackLocationToNext为下一个较低的驱动程序设置新的堆栈位置。

IoCopyCurrentIrpStackLocationToNext

void IoCopyCurrentIrpStackLocationToNext(
  [in, out] PIRP Irp
);

IoCopyCurrentIrpStackLocationToNext 将 IRP 参数从其堆栈位置复制到下一个较低驱动程序的堆栈位置。

IoCallDriver

#define IoCallDriver(a,b)   \
        IofCallDriver(a,b)
);


NTSTATUS IofCallDriver(
  PDEVICE_OBJECT        DeviceObject,
  __drv_aliasesMem PIRP Irp
);

IoCallDriver让传入的DeviceObject处理IRP,一般我们绑定设备后,派遣函数中首先使用IoSkipCurrentIrpStackLocationIoCopyCurrentIrpStackLocationToNext,然后使用IoCallDriver(pAttachedDeviceObject,pIrp),为了传给到目标设备栈,pAttachedDeviceObject是目标设备栈的最顶层设备。文章来源地址https://www.toymoban.com/news/detail-400604.html

到了这里,关于Windows 驱动开发 新手入门(四)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python保姆级教程 数据类型—新手小白入门必看系列

    推荐使用压缩软件和杀毒软件 7 - zip 使用火绒 优点: 代码说明 没注释的代码 有注释的代码 不让解释器执行注释的那句话 单行注释快捷键:ctrl + ? \\\"\\\"\\\"\\\"\\\"\\\" (三个双引号) 185730213551 什么是变量:可以改变的量 计算机用来存贮数据的盒子,想用这个数据,就直接那盒子就好了

    2024年02月16日
    浏览(39)
  • 【MySQL新手入门系列二】:手把手教你入门MySQL - 数据库及数据表操作

    如果您是一位刚刚开始学习MySQL的新手,本文将为您提供一些实用的入门知识和技巧,帮助您快速上手。 【MySQL新手入门系列一】:手把手教你入门MySQL 前面我们已经大致讲了一下mysql的安装等介绍,本篇文章将以windows为例,介绍MySQL的数据库及数据表的操作(增删改查)。

    2024年02月10日
    浏览(59)
  • MUI框架从新手入门【webapp开发教程】

    性能和体验的差距,一直是mobile app开发者放弃HTML5的首要原因。 浏览器天生的切页白屏、不忍直视的转页动画、浮动元素的抖动、无法流畅下拉刷新等问题,这些都让HTML5开发者倍感挫败,尤其拿到Android低端机运行,摔手机的心都有; 另一方面,浏览器默认控件样式又少又

    2024年02月04日
    浏览(33)
  • 【虚幻4】UE4初学者系列教程基础篇-全中文新手入门教程

    一、 创建工程文件 (1)虚拟项目浏览器 (2)虚拟文件夹的结构 (3) 初学者内容包 二、虚幻引擎编辑界面介绍 (1)菜单栏 (2)关卡编辑器:工具栏  (3)“模式”面板  (4)“内容浏览器”面板 (5)视口面板 (6) 世界大纲视图 (7)细节面板 三、视口导航 四、

    2024年02月13日
    浏览(33)
  • 【虚幻引擎】UE4初学者系列教程基础篇-全中文新手入门教程

    一、 创建工程文件 (1)虚拟项目浏览器 (2)虚拟文件夹的结构 (3) 初学者内容包 二、虚幻引擎编辑界面介绍 (1)菜单栏 (2)关卡编辑器:工具栏  (3)“模式”面板  (4)“内容浏览器”面板 (5)视口面板 (6) 世界大纲视图 (7)细节面板 三、视口导航 四、

    2024年02月04日
    浏览(60)
  • 【MySQL新手入门系列五】:MySQL的高级特性简介及MySQL的安全简介

    前面我们已经大致讲了一下mysql的安装等介绍,MySQL 中的“新增、删除与修改”操作。 MySQL 作为一款业界领先的数据库管理系统,具备许多高级特性,本文将重点介绍MySQL中的索引、视图、存储过程、触发器和事务处理。 【MySQL新手入门系列一】:手把手教你入门MySQL 【MySQ

    2024年02月11日
    浏览(37)
  • 【虚幻引擎】UE4初学者系列教程VR篇-全中文新手入门教程

    1.有vr来配置         无论使用的是何种头戴显示器,开发使用 SteamVR 的 VR 项目时都需要下载并安装 Steam,才能访问 SteamVR。以下部分将说明下载安装 SteamVR 的方法。         首先需要从 Steam 站点(http://store.steampowered.com/)下载并安装 Steam客户端。Steam 安装完成后,用

    2024年04月10日
    浏览(39)
  • Java开发环境配置“JDK”超详细整理,适合新手入门

    目录 一、什么是JDK? 二、Java中JDK8、JDK17该怎么选择? 三、JDK和JRE是什么关系? 四、JDK包含的基本组件 五、JDK下载步骤 JDK 安装 1、双击运行安装包,出现安装程序,点击下一步 2、修改JDK安装目录 3、根据提示安装完成,这就完成jdk安装了,可以直接点关闭了 JDK 环境配置

    2023年04月08日
    浏览(39)
  • 界面开发框架Qt新手入门教程:Dir视图使用实例

    Qt 是目前最先进、最完整的跨平台C++开发工具。它不仅完全实现了一次编写,所有平台无差别运行,更提供了几乎所有开发过程中需要用到的工具。如今,Qt已被运用于超过70个行业、数千家企业,支持数百万设备及应用。 点击获取Qt Widget组件下载 本示例演示了树形视图的用

    2024年02月08日
    浏览(35)
  • Python 安装教程,新手入门(超详细)含Pycharm开发环境安装教程

    目录 一、Python介绍 二、Python安装教程 (一)Python的下载 (二)Python的安装 三、Pycharm开发工具的安装 (一)Pycharm介绍 (二)Pycharm的下载 (三)Pycharm的安装 ​        Python由荷兰数学和计算机科学研究学会的吉多·范罗苏姆于1990年代初设计,作为一门叫做ABC语言的替

    2024年01月20日
    浏览(70)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包