IO交互模式中的DeviceIOControl与驱动层交互有三种:缓冲区模式、直接访问模式、其他模式,这里本人学习的是缓冲区访问模式,原理如图:

驱动中最好不要直接访问用户模式下的内存地址,使用缓冲区方式可以避免程序员访问内存模式下的内存地址。
Win32API DeviceIoControl的内部,用户提供的输入缓冲区的内容呗复制到IRP中的pIrp->AssociateIrp.SystemBuffer内存地址,复制的字节数是由DeviceIoControl指定的输入字节数。
派遣函数可以读取pIrp->AssociateIrp.SystemBuffer的内存地址,从而获得应用程序提供的输入缓冲数据。另外,派遣函数还可以写入pIrp->AssociateIrp.SystemBuffer的内存地址,被当做设备输出的数据。操作系统会将这个地址的数据再次复制到DeviceIoControl提供的输出缓冲区。复制的字节数有pIrp->IoStatus.Information指定。DeviceIoControl也可以通过它的第七个参数(lpBytesReturned)得到这个操作字节数。
派遣函数先通过IoGetCurrentIrpStackLocation函数->得到当前IO堆栈(IO_STACK_LOCATION)->派遣函数通过stack->Parameters.DeviceIoControl.InputBufferLength得到输入缓冲区大小->通过stack->Parameters.DeviceIoControl.OutputBufferLength得到输出缓冲区大小->最后通过stack->Parameters.DeviceIoControl.IoControlCode得到IOCTL
在派遣函数中通过C语言中的switch处理不同的IOCTL

代码:

BufferedIO.c

 #include "BufferedIO.h"

 NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath)
{
NTSTATUS Status = STATUS_SUCCESS;
PDEVICE_OBJECT DeviceObject = NULL;
UNICODE_STRING DeviceObjectName;//设备对象名称
UNICODE_STRING DeviceLinkName; //设备连接名称
int i = ; DriverObject->DriverUnload = DriverUnload; //1.创建设备对象名称
RtlInitUnicodeString(&DeviceObjectName, DEVICE_OBJECT_NAME); //2.创建设备对象
Status = IoCreateDevice(
DriverObject,//驱动程序对象.
NULL, //指定驱动程序为设备扩展对象而定义的结构体的大小.
&DeviceObjectName, //(可选的参数)指向一个以零结尾的包含Unicode字符串的缓冲区, 那是这个设备的名称, 该字符串必须是一个完整的设备路径名.
FILE_DEVICE_UNKNOWN, //指定一个由一个系统定义的FILE_DEVICE_XXX常量, 表明了这个设备的类型
, //一个或多个系统定义的常量, 连接在一起, 提供有关驱动程序的设备其他信息.
FALSE, //设备是独占的,独占的话设置为TRUE,非独占设置为FALSE.一般FALSE
&DeviceObject
);//成功时返回STATUS_SUCCESS if (!NT_SUCCESS(Status))
{
return Status;
} //3.创建设备连接名称
RtlInitUnicodeString(&DeviceLinkName, DEVICE_LINK_NAME); //4.将设备连接名称与设备名称关联
Status = IoCreateSymbolicLink(
&DeviceLinkName,
&DeviceObjectName
);//创建一个设备链接。
//驱动程序虽然有了设备名称,但是这种设备名称只能在内核态可见,
//而对于应用程序是不可见的,因此,驱动需要要暴露一个符号链接,
//该链接指向真正的设备名称 if (!NT_SUCCESS(Status))
{
IoDeleteDevice(DeviceObject);
return Status;
} //Ring3请求->设备对象-> 驱动对象找到派遣历程 //5.设置符合我们代码的派遣历程
for (i = ; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
{
//MinorFunction ring3 与ring0 的协议 DriverObject->MajorFunction[i] = PassThroughDispatch;
} //IRP_MJ_DEVICE_CONTROL DeviceIOControl函数产生
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ControlThroughDispatch; return Status;
} //基本派遣历程
NTSTATUS PassThroughDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
Irp->IoStatus.Status = STATUS_SUCCESS; //LastError()
Irp->IoStatus.Information = ; //ReturnLength
IoCompleteRequest(Irp, IO_NO_INCREMENT); //将Irp返回给Io管理器
return STATUS_SUCCESS;
} NTSTATUS ControlThroughDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
NTSTATUS Status;
ULONG_PTR Informaiton = ;
PVOID InputData = NULL;
ULONG InputDataLength = ;
PVOID OutputData = NULL;
ULONG OutputDataLength = ;
ULONG IoControlCode = ; //1.得到当前IO堆栈(IO_STACK_LOCATION)
PIO_STACK_LOCATION IoStackLocation = IoGetCurrentIrpStackLocation(Irp); //Irp堆栈 //2.看笔记或者代码中的图 而且在Ring0层中都是SystemBuffer
InputData = Irp->AssociatedIrp.SystemBuffer;
OutputData = Irp->AssociatedIrp.SystemBuffer; //得到输入缓冲区大小
InputDataLength = IoStackLocation->Parameters.DeviceIoControl.InputBufferLength;
//输出缓冲区大小
OutputDataLength = IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength; //3.得到IOCTL
IoControlCode = IoStackLocation->Parameters.DeviceIoControl.IoControlCode; //在派遣函数中通过Cswitch处理不同的IOCTL
switch (IoControlCode)
{
case CTL_HELLO:
{
if (InputData != NULL && InputDataLength > )
{
DbgPrint("%s\r\n", InputData);
}
if (OutputData != NULL&&OutputDataLength >= strlen("Ring0->Ring3") + )
{
memcpy(OutputData, "Ring0->Ring3", strlen("Ring0->Ring3") + );
Status = STATUS_SUCCESS;
Informaiton = strlen("Ring0->Ring3") + ;
}
else
{
Status = STATUS_INSUFFICIENT_RESOURCES; //内存不够
Informaiton = ;
} break;
}
default:
break;
} Irp->IoStatus.Status = Status; //Ring3 GetLastError();
Irp->IoStatus.Information = Informaiton;
IoCompleteRequest(Irp, IO_NO_INCREMENT); //将Irp返回给Io管理器 return Status;
} VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING DeviceLinkName;
PDEVICE_OBJECT v1 = NULL;
PDEVICE_OBJECT DeleteDeviceObject = NULL; RtlInitUnicodeString(&DeviceLinkName, DEVICE_LINK_NAME);
IoDeleteSymbolicLink(&DeviceLinkName); RtlInitUnicodeString(&DeviceLinkName, DEVICE_LINK_NAME);
IoDeleteSymbolicLink(&DeviceLinkName); DeleteDeviceObject = DriverObject->DeviceObject;
while (DeleteDeviceObject != NULL)
{
v1 = DeleteDeviceObject->NextDevice;
IoDeleteDevice(DeleteDeviceObject);
DeleteDeviceObject = v1;
} DbgPrint("DriverUnload()\r\n");
} /*
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. Thise 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 DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _DEVICE_OBJECT {
CSHORT Type;
USHORT Size;
LONG ReferenceCount;
struct _DRIVER_OBJECT *DriverObject;
struct _DEVICE_OBJECT *NextDevice; //
struct _DEVICE_OBJECT *AttachedDevice;
struct _IRP *CurrentIrp;
PIO_TIMER Timer;
ULONG Flags; // See above: DO_...
ULONG Characteristics; // See ntioapi: FILE_...
__volatile PVPB Vpb;
PVOID DeviceExtension;
DEVICE_TYPE DeviceType;
CCHAR StackSize;
union {
LIST_ENTRY ListEntry;
WAIT_CONTEXT_BLOCK Wcb;
} Queue;
ULONG AlignmentRequirement;
KDEVICE_QUEUE DeviceQueue;
KDPC Dpc; //
// The following field is for exclusive use by the filesystem to keep
// track of the number of Fsp threads currently using the device
// ULONG ActiveThreadCount;
PSECURITY_DESCRIPTOR SecurityDescriptor;
KEVENT DeviceLock; USHORT SectorSize;
USHORT Spare1; struct _DEVOBJ_EXTENSION *DeviceObjectExtension;
PVOID Reserved; } DEVICE_OBJECT;
*/

BufferIO.h

 #include <ntifs.h>

 //设备与设备之间通信
#define DEVICE_OBJECT_NAME L"\\Device\\BufferedIODeviceObjectName" //设备与Ring3之间通信
#define DEVICE_LINK_NAME L"\\DosDevices\\BufferedIODeviceLinkName" //Ring3 Ring0 握手协议 CTL_HELLO
#define CTL_HELLO \
CTL_CODE(FILE_DEVICE_UNKNOWN,0x830,METHOD_BUFFERED,FILE_ANY_ACCESS) NTSTATUS PassThroughDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp);
NTSTATUS ControlThroughDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp); VOID DriverUnload(PDRIVER_OBJECT DriverObject);

缓冲区IO(Ring3).cpp

 // 缓冲区IO(Ring3).cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <windows.h> #define DEVICE_LINK_NAME L"\\\\.\\BufferedIODeviceLinkName"//Ring3格式 #define CTL_HELLO \
CTL_CODE(FILE_DEVICE_UNKNOWN,0x830,METHOD_BUFFERED,FILE_ANY_ACCESS) /*
DeviceIoControl内部会使操作系统创建一个
IRP_MJ_DEVICE_CONTROL类型的IRP,然后操作系统将这个IRP转发到派遣函数 我们用DeviceIoControl定义除了读写之外的其他操作,让Ring3程序与Ring0程序通信 e.g:自定义一种IO控制码,然后用DeviceIoControl将这个控制码和请求一起传递给驱动程序
派遣函数中,分别对不同的IO控制码进行处理 BOOL WINAPI DeviceIoControl(
_In_ HANDLE hDevice, //已经打开的设备
_In_ DWORD dwIoControlCode,//控制码
_In_opt_ LPVOID lpInBuffer, //输入缓冲区
_In_ DWORD nInBufferSize, //输入缓冲区大小
_Out_opt_ LPVOID lpOutBuffer, //输出缓冲区
_In_ DWORD nOutBufferSize, //输出缓冲区大小
_Out_opt_ LPDWORD lpBytesReturned,//实际返回字节数
_Inout_opt_ LPOVERLAPPED lpOverlapped //是否OverLapp
); */ int main()
{ HANDLE DeviceHandle = CreateFile(
DEVICE_LINK_NAME,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL); if (DeviceHandle == INVALID_HANDLE_VALUE)
{
return ;
} char BufferData = NULL;
DWORD ReturnLength = ; //操作系统内部是操作系统创建IRP_MJ_DEVICE_CONTROL类型的IRP
//Ring3->Ring0
BOOL IsOk = DeviceIoControl(
DeviceHandle, //已经打开的设备
CTL_HELLO,//控制码
"Ring3->Ring0",//输入缓冲区
strlen("Ring3->Ring0") + ,//输入缓冲区大小
(LPVOID)BufferData,//输出缓冲区
,//输出缓冲区大小
&ReturnLength,//实际返回字节数
NULL//是否OVERLAP操作
); if (IsOk == FALSE)
{
//上面的nOutBufferSize = 0 所以必定发生错误 int LastError = GetLastError(); if (LastError == ERROR_NO_SYSTEM_RESOURCES)
{
char BufferData[MAX_PATH] = { }; //Ring3请求->设备对象-> 驱动对象找到派遣历程 IsOk = DeviceIoControl(
DeviceHandle,
CTL_HELLO,
"Ring3->Ring0",
strlen("Ring3->Ring0") + ,
(LPVOID)BufferData,
MAX_PATH,
&ReturnLength,
NULL); if (IsOk == TRUE)
{
printf("%s\r\n", BufferData);
}
}
} if (DeviceHandle != NULL)
{
CloseHandle(DeviceHandle);
DeviceHandle = NULL;
}
printf("Input AnyKey To Exit\r\n"); getchar(); return ;
}

DeviceIOControl与驱动层 - 缓冲区模式的更多相关文章

  1. DeviceIoControl 应用层如何和驱动层通信?

    调用的方法之一的DeviceIoControl 驱动层提供设备名 例如filedisk 在驱动层 首先先是注册列表 用winObj查看 filedisk的驱动对象 但是 这八个对象时怎么生成的呢? 我 ...

  2. Linux 网卡驱动学习(六)(应用层、tcp 层、ip 层、设备层和驱动层作用解析)

    本文将介绍网络连接建立的过程.收发包流程,以及当中应用层.tcp层.ip层.设备层和驱动层各层发挥的作用. 1.应用层 对于使用socket进行网络连接的server端程序.我们会先调用socket函 ...

  3. 从驱动层分析android的Binder机制-android学习之旅(83)

    前言及知识准备 Binder驱动程序 Service组件的注册和启动 Clinet应用获取服务 本次主要介绍Android平台下Binder进程间机制.从机制的组成出发,将按照Binder驱动程序.B ...

  4. Linux 驱动层实现阻塞和非阻塞

    linux应用层的函数默认是阻塞型的,但是要想真正实现阻塞,还需要驱动的支持才行. 例:open().scanf().fgets().read().accept() 等 1.默认情形,驱动层不实现阻塞 ...

  5. binder学习笔记(十)—— 穿越到驱动层

    Binder驱动层的代码在kernel/goldfish/drivers/staging/android下的binder.c和binder.h.Android源码是不带Linux内核的,驱动正是在这个 ...

  6. 2、CC2541芯片中级教程-OSAL操作系统(进一步了解-OLED && 普通按键和5方向按键-中断!!!)这个系统驱动层和应用层不一样~

    本文根据一周CC2541笔记汇总得来—— 适合概览和知识快速索引—— 全部链接: 中级教程-OSAL操作系统\OSAL操作系统-实验01 OSAL初探 [插入]SourceInsight-工程建立方法 ...

  7. Minifilter微过滤框架:框架介绍以及驱动层和应用层的通讯

    minifilter是sfilter后微软推出的过滤驱动框架.相比于sfilter,他更容易使用,需要程序员做的编码更简洁. 系统为minifilter专门制作了一个过滤管理器,这个管理器本身其实是一 ...

  8. 老斜两宗事-七层代理模式还是IP层VPN

    1.七层代理模式还是IP层VPN 非常多人会问,我究竟是使用代理模式呢,还是使用VPN模式,假设我想数据在中间不安全的链路上实现加密保护的话.这个问题有一个背景.那就是,你想保护你的数据,能够使用VP ...

  9. 14.LINUX-platform机制实现驱动层分离(详解)

    版权声明:本文为博主原创文章,未经博主允许不得转载. 本节目标:        学习platform机制,如何实现驱动层分离 1.先来看看我们之前分析输入子系统的分层概念,如下图所示: 如上图所示,分 ...

随机推荐

  1. Chrome (开发者工具)快捷键

    https://9iphp.com/web/javascript/chrome-devtools-shortcuts.html https://www.cnblogs.com/davidwang456 ...

  2. <--------------------------StringBuffer的常用方法------------------------------>

    StringBuffer定义: 是可变字符数组,是线程安全的可变字符序列. StringBuffer和String的区别: String是一个不可变的字符序列. 实例: public class St ...

  3. jvm系列(1):JVM问答

    一:JVM基础知识 1)Java 是如何实现跨平台的? 注意:跨平台的是 Java 程序,而不是 JVM.JVM 是用 C/C++ 开发的,是编译后的机器码,不能跨平台,不同平台下需要安装不同版本的 ...

  4. 现在的企业用到的Java开发主流框架有哪些

    虽然Java一直被唱衰,但是直到现在Java软件开发也坚持霸主地位不动摇.毫无疑问,Java是目前最热门的编程语言之一.随着Java面向对象语言的流行以及多层架构应用的出现,使得应用程序的可复用性得到 ...

  5. prime docker-compose 环境运行试用

    prime 是一款基于graphql的开源cms,功能点很不错,但是出来不久,还是有好多bug的 官方暂时没有提供docker 的运行方式,为了方便测试,搞了以及docker-compose 测试的 ...

  6. #define vs. const vs enum

    In one word, using const is better than define. enum is the best. There are lots of discussions. I p ...

  7. 改变codeblocks里面各种注释的颜色。

    ->Setting->Editor->Syntax highlighting->“Comment(normal)” /* 改变块注释颜色 */"Comment lin ...

  8. 01 Linux简介

    1.Linux简介 UNIX与Linux发展史 Unix在1969年,美国贝尔实验室的肯汤普森在DEC PDP-7机器上开发出了UNIX系统. Linux出现于1991年,是由芬兰赫尔辛基大学学生李纳 ...

  9. C# to IL 2 IL Basics(IL基础)

    This chapter and the next couple of them will focus on and elicit a simple belief of ours,that if yo ...

  10. C# to IL 1 Introduction to Microsoft’s IL(MSIL 介绍)

    The code that we write in a programming language like C#, ASP+ or in any other .NETcompatible langua ...