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 ;
}

最新文章

  1. 一步步开发自己的博客 .NET版(5、Lucenne.Net 和 必应站内搜索)
  2. JustWe-WebServer Android上的Http服务器
  3. css3动画特效:上下晃动的div
  4. VS2010中使用GDAL(一)
  5. Caused by: org.springframework.core.NestedIOException: ASM ClassReader failed to parse class file
  6. Android IOS WebRTC 音视频开发总结(三四)-- windows.20150706
  7. Python 异常结构
  8. 阿里巴巴SUI Mobile的使用
  9. Delphi ADOQuery的速度优化 转
  10. WPF与混淆器
  11. mysql5.6升级到5.7后Sequel Pro无法连接解决
  12. WinForm中 Asp.Net Signalr消息推送测试实例
  13. 新硬盘挂载-fdisk+mount案例实操
  14. python六十一课——高阶函数之reduce
  15. 详细且透彻的分析PCA原理
  16. 22.纯 CSS 创作出美丽的彩虹条纹文字
  17. mac下安装rzsz
  18. POJ 1080( LCS变形)
  19. angularJS1笔记-(17)-ng-bind-html指令
  20. bzoj千题计划157:bzoj1220:[HNOI2002]跳蚤

热门文章

  1. [动态差分+二维前缀和][小a的轰炸游戏]
  2. day1 python学习
  3. sqler sql 转rest api 防止sql 注入
  4. drone 1.0 新的构建徽章特性
  5. A* 寻路学习
  6. 基于SVN提交历史筛选作者并修改文件内容
  7. oracle之 ORA-12557: TNS: 协议适配器不可加载
  8. dockerfile创建php容器(安装memcached、redis、gd、xdebug扩展)
  9. 怎么用fiddler抓APP的包
  10. mysql 主从复制change master to