windows驱动开发7:应用程序和驱动程序的通信

这篇具有很好参考价值的文章主要介绍了windows驱动开发7:应用程序和驱动程序的通信。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

应用程序和驱动程序的通信

一、基础介绍

1.1 设备与驱动的关系

设备由驱动去创建,访问一个设备,是首先得访问驱动。如果驱动在卸载的时候没有删除符号,r3下也是不能去访问设备的。

驱动程序和系统其他组件之间的交互是通过给设备发送或者接受发给设备的请求来交互的。换句话说,一个没有任何设备的驱动是不能按规范方式和系统交互的。当然也不会收到任何IRP,分发函数也失去了意义。如果驱动程序要和应用程序之间通信,则需要生成设备。此外还必须为设备生成应用程序可以访问的符号链接。

也就是说,应用程序与驱动的交互是通过设备来完成的,设备成了中间桥梁。下文中的符号链接又成了设备名的中间桥梁。记住,核心中介是设备。其他都是为他们的通信提供的机制。

1.2 设备符号链接名与设备名

Ring3不能直接访问设备,需要中间桥梁。这个中间桥梁是Ring0驱动为设备名注册的链接符号(Symbol Link)。
windows驱动开发7:应用程序和驱动程序的通信

从图中可以看出,R3要访问设备,是通过设备符号名去访问设备的,而R3应用层下的设备符号名和设备管理器中的设备符号名有出入,必须,也只能写成\.\设备符号名 的方式 ,系统会自动转为??\设备符号名 ,紧接着通过设备符号名这个中间桥梁可以转化为真正的R0下的设备名。

也就是说,符号链接名在应用层只是简单的符号转化过程,有些类似宏定义,设备符号名主体是相同的。而设备名和设备符号名可以不相同。因为设备符号名仅仅是个中间桥梁。

总结:

  1. R0下的设备名格式为\Device\自定义设备名
  2. R0下的设备符号名格式为\??\自定义符号名,其中自定义符号名自定义设备名可以不一致。
  3. R3下不能直接访问设备,只能用设备符号名去访问设备,但是也不能直接使用\??\设备符号名去获得设备名
  4. R3要访问设备,必须使用\\.\设备符号名,这个设备符号名由R0给定。
1.3 通信机制
  1. 应用程序和驱动程序的通信是通过IRP (i/o request packet) (IO请求包) 来完成的。
  2. 利用其它进程通信方式,如socket、pip、共享内存等(注意r0的api调用方式不一致)

二、IRP方式

2.1 定义IO控制码

可以看做一种通信协议,宏定义:

#define CTL_CODE( DeviceType, Function, Method, Access ) (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))

可以看到,这个宏四个参数,自然是一个32位分成了4部分:

  • 高16位存储设备类型
  • 14~15位访问权限
  • 2~13位操作功能
  • 最后0/1两位就是确定缓冲区是如何与I/O和文件系统数据缓冲区进行数据传递方式

自定义CTL_CODE

#define IOCTL_TEST_BUFFERED  CTL_CODE(FILE_DEVICE_UNKNOWN, 0x900, METHOD_BUFFERED, FILE_ANY_ACCESS)
  • IOCTL_TEST_BUFFERED:生成的IRP的MinorFunction
  • FILE_DEVICE_UNKNOWN:设备对象的类型。设备类型可参考:http://blog.csdn.net/liyun123gx/article/details/38058965
  • 0x900 :自定义的IO控制码。自己定义时取0x800到0xFFF,因为0x0到0x7FF是微软保留的。
  • METHOD_BUFFERED:缓冲区进行数据传递方式
  • FILE_ANY_ACCESS :数据的操作模式。
内存访问方式

有四种方式:

#define METHOD_BUFFERED     0
#define METHOD_IN_DIRECT    1
#define METHOD_OUT_DIRECT 2
#define METHOD_NEITHER      3

METHOD_BUFFERED:表示系统将用户的输入输出都经过pIrp->AssociatedIrp.SystemBuffer来缓冲,因此这种方式的通信比较安全。
windows驱动开发7:应用程序和驱动程序的通信

METHOD_IN_DIRECTMETHOD_OUT_DIRECT:表示系统会将输入缓冲在pIrp->AssociatedIrp.SystemBuffer中,并将输出缓冲区锁定,然后在内核模式下重新映射一段地址,这样也是比较安全的。

METHOD_IN_DIRECT和METHOD_OUT_DIRECT可称为"直接方式",是指系统依然对Ring3的输入缓冲区进行缓冲,但是对Ring3的输出缓冲区并没有缓冲,而是在内核中进行了锁定。这样Ring3输出缓冲区在驱动程序完成I/O请求之前,都是无法访问的,从一定程度上保障了安全性。这两种方式,对于Ring3的输入缓冲区和METHOD_BUFFERED方式是一致的。对于Ring3的输出缓冲区,首先由系统锁定,并使用pIrp->MdlAddress来描述这段内存,驱动程序需要使用MmGetSystemAddressForMdlSafe函数将这段内存映射到内核内存地址(OutputBuffer),然后可以直接写入OutputBuffer地址,最终在驱动派遣例程返回后,由系统解除这段内存的锁定。

METHOD_IN_DIRECT和METHOD_OUT_DIRECT方式的区别,仅在于打开设备的权限上,当以只读权限打开设备时,METHOD_IN_DIRECT方式的IoControl将会成功,而METHOD_OUT_DIRECT方式将会失败。如果以读写权限打开设备,两种方式都会成功。
windows驱动开发7:应用程序和驱动程序的通信

METHOD_NEITHER:“其他方式”,虽然通信的效率提高了,但是不够安全。驱动的派遣函数中输入缓冲区可以通过I/O堆栈(IO_STACK_LOCATION)的stack->Parameters.DeviceIo Control.Type3InputBuffer得到。输出缓冲区可以通过pIrp->UserBuffer得到。由于驱动中的派遣函数不能保证传递进来的用户输入和输出地址,因此最好不要直接去读写这些地址的缓冲区。应该在读写前使用ProbeForRead和ProbeForWrite函数探测地址是否可读和可写。

METHOD_ NEITHER方式是不进行缓冲的,在驱动中可以直接使用Ring3的输入输出内存地址,驱动程序可以通过pIrpStack->Parameters.DeviceIoControl.Type3InputBuffer得到Ring3的输入缓冲区地址(其中pIrpStack是IoGetCurrentIrpStackLocation(pIrp)的返回);通过pIrp-> UserBuffer得到Ring3的输出缓冲区地址。

由于METHOD_NEITHER方式并不安全,因此最好对Type3InputBuffer读取之前使用ProbeForRead函数进行探测,对UserBuffer写入之前使用ProbeForWrite函数进行探测,当没有发生异常时,再进行读取和写入操作。
windows驱动开发7:应用程序和驱动程序的通信
windows驱动开发7:应用程序和驱动程序的通信

2.2 定义驱动设备名,符号链接名

关于在Ring0层中要设置驱动设备名的同时还要设置符号链接名的原因,是因为只有符号链接名才可以被用户模式下的应用程序识别。

如果IoCreateDevice中没有指定设备名称,那么I/O管理器会自动分配一个数字作为设备的名称。

// 驱动设备名:设备与设备之间通信
#define DEVNAME L"\\Device\\kmdfDriver2"

// 符号链接名:设备与Ring3之间通信
#define LNKNAME L"\\??\\kmdfDriver2"
2.3 设备同驱动通信

驱动程序要做的最后一步,先用IoCreateDevice函数创建设备对象,再用IoCreateSymbolicLink将符号链接名与设备对象名称关联,大功告成,等待IO控制码。


// 创建设备对象名称
RtlInitUnicodeString(&DeviceObjectName,DEVICE_OBJECT_NAME);
// 创建设备对象
Status = IoCreateDevice(DriverObject,NULL,
    &DeviceObjectName,
    FILE_DEVICE_UNKNOWN,
    0, FALSE,
    &DeviceObject);
if (!NT_SUCCESS(Status))
{
   
    return Status;
}

// 创建设备连接名称
RtlInitUnicodeString(&DeviceLinkName, DEVICE_LINK_NAME);
// 将设备连接名称与设备名称关联
Status = IoCreateSymbolicLink(&DeviceLinkName,&DeviceObjectName);

if (!NT_SUCCESS(Status))
{
   
    IoDeleteDevice(DeviceObject);
    return Status;
}       

驱动程序铺垫打理好之后,应用程序就可以由符号链接名通过CreateFile函数获取到设备句柄DeviceHandle,再用本场的主角,DeviceIoControl通过这个DeviceHandle发送控制码了。文章来源地址https://www.toymoban.com/news/detail-405179.html

BOOL WINAPI DeviceIoControl(
  _In_         HANDLE hDevice,       // CreateFile函数打开的设备句柄
  _In_         DWORD dwIoControlCode,// 自定义的控制码
  _In_opt_     LPVOID lpInBuffer,    // 输入缓冲区
  _In_         DWORD nInBufferSize,  // 输入缓冲区的大小
  _Out_opt_    LPVOID lpOutBuffer,   // 输出缓冲区
  _In_         DWORD nOutBufferSize, // 输出缓冲区的大小
  _Out_opt_    LPDWORD lpBytesReturned, // 实际返回的字节数,对应驱动程序中pIrp->IoStatus.Information。
  _Inout_opt_  LPOVERLAPPED lpOverlapped // 重叠操作结构指针。同步设为NULL,DeviceIoControl将进行阻塞调用;否则,应在编程时按异步操作设计
);
HANDLE CreateFile(
  LPCTSTR lpFileName,                         // 打开的文件名
  DWORD dwDesiredAccess,                    // 访问权限
  DWORD dwShareMode,                      // 共

到了这里,关于windows驱动开发7:应用程序和驱动程序的通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • LCD驱动程序——Framebuffer应用编程

    在 Linux 系统中通过 Framebuffer 驱动程序来控制 LCD。 Frame 是帧的意思 , buffer 是缓冲的意思 ,这意味着 Framebuffer 就是一块内存,里面保存着一帧图像。Framebuffer 中保存着一帧图像的每一个像素颜色值,假设 LCD 的分辨率是 1024x768,每一个像素的颜色用 32 位来表示,那么 Frame

    2024年02月06日
    浏览(34)
  • 5.2.10.应用程序如何调用驱动 mknod /dev/test c 250 0 创建设备文件,应用app 程序 调用 我们 驱动 壳子

    5.2.10.应用程序如何调用驱动 5.2.10.1、驱动设备文件的创建 (1)何为设备文件     索引驱动 (2)设备文件的关键信息是:设备号 = 主设备号 + 次设备号,使用ls -l去查看设备文件,就可以得到这个设备文件对应的主次设备号。         4颗LED不可能 都占用 主设备号,设备号

    2024年02月16日
    浏览(42)
  • 第五章 I/O管理 五、输入/输出应用程序接口&设备驱动程序接口

    目录 一、应用程序接口 二、阻塞和非阻塞I/O 阻塞I/O: 非阻塞I/O: 三、设备驱动程序 以前的统一接口不适用了,现在改为了几种不同的接口 阻塞I/O: 应用程序发出I/O系统调用,进程需转为阻塞态等待。 eg:字符设备接口―一从键盘读一个字符get 非阻塞I/O: 应用程序发出I/O系统调

    2024年02月07日
    浏览(45)
  • ODBC 在指定的DSN中,驱动程序和应用程序之间的体系结构不匹配

    常规办法就是64位或32位匹配,如果解决不了,往下看。 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓解决方案↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 解压AccessDatabaseEngine_X64.exe,用orca编辑器打开AceRedist.

    2024年02月02日
    浏览(76)
  • 事件驱动编程:如何在应用程序中处理用户输入和交互

    [toc] 引言 1.1. 背景介绍 随着互联网技术的快速发展,应用程序被广泛应用于人们的生活和工作中。在这些应用程序中,用户输入和交互是必不可少的组成部分。如何优雅地处理用户输入和交互,让应用程序更加符合用户的使用习惯,是摆在每个程序员面前的一个重要问题。

    2024年02月07日
    浏览(59)
  • LangChain入门:构建LLM驱动的应用程序的初学者指南

    LangChain DemoGPT         你有没有想过如何使用大型语言模型(LLM)构建强大的应用程序?或者,也许您正在寻找一种简化的方式来开发这些应用程序?那么你来对地方了!本指南将向您介绍LangChain,这是一个简化构建LLM驱动的应用程序的过程的工具。我们还将深入研究 

    2024年02月12日
    浏览(41)
  • Node.js 中的事件驱动编程:构建强大应用程序的利器

    引言: 在当今高度并发的网络环境下,构建高效、响应迅速的应用程序是开发人员的一项重要任务。Node.js,作为一种基于事件驱动编程模型的 JavaScript 运行环境,为开发人员提供了一个强大的工具。本文将介绍 Node.js 中的事件模型以及如何使用事件驱动编程模式构建强大的

    2024年02月10日
    浏览(52)
  • Rabbit R1是一款AI驱动的小工具,可以代替你使用应用程序

      每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领域的领跑者。点击订阅,与

    2024年02月19日
    浏览(46)
  • 探索在云原生环境中构建的大数据驱动的智能应用程序的成功案例,并分析它们的关键要素。

    🎈个人主页:程序员 小侯 🎐CSDN新晋作者 🎉欢迎 👍点赞✍评论⭐收藏 ✨收录专栏:云计算 ✨文章内容:云原生 🤝希望作者的文章能对你有所帮助,有不足的地方请在评论区留言指正,大家一起学习交流!🤗 在云原生环境中构建大数据驱动的智能应用程序已经成为许多

    2024年02月10日
    浏览(44)
  • Windows 驱动程序签名教程(一) --- 开发测试篇

    1.使用微软WHQL签名 2.使用2013-2015年签发的驱动签名,已过期未吊销未拉黑(不知道什么时候打个补丁会修复). 1.使用微软WHQL签名 2.使用过期签名的sha1 sha256都可以正常跑 1.使用微软WHQL签名,SHA256的签名需要打补丁支持(KB3033929). 2.SHA1签名 1.Windows 10 可以直接 输入命令: 2.如果还不

    2024年02月15日
    浏览(36)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包