IO设备控制操作

除了 读设备和  写设备 外  还可以有一个API DeviceIoControl 操作设备 创建一个IRP_MJ_DEVICE_CONTROL 类型的IRP 

DeviceIoControl

hDevice Long,设备句柄
dwIoControlCode Long,应用程序调用驱动程序的控制命令,就是IOCTL_XXX IOCTLs。
lpInBuffer Any,应用程序传递给驱动程序的数据缓冲区地址。
nInBufferSize Long,应用程序传递给驱动程序的数据缓冲区大小,字节数。
lpOutBuffer Any,驱动程序返回给应用程序的数据缓冲区地址。
nOutBufferSize Long,驱动程序返回给应用程序的数据缓冲区大小,字节数。
lpBytesReturned Long,驱动程序实际返回给应用程序的数据字节数地址。
lpOverlapped OVERLAPPED,这个结构用于重叠操作。针对同步操作,请用ByVal As Long传递零值


应用程序 源码:

头文件:

#ifndef IOCTLS_H
#define IOCTLS_H


#ifndef CTL_CODE
	#pragma message("CTL_CODE undefined. Include winioctl.h or wdm.h")
#endif


#define IOCTL_TEST1 CTL_CODE(
			FILE_DEVICE_UNKNOWN, 
			0x800, 
			METHOD_BUFFERED, 
			FILE_ANY_ACCESS)


#define IOCTL_TEST2 CTL_CODE(
			FILE_DEVICE_UNKNOWN, 
			0x801, 
			METHOD_IN_DIRECT, 
			FILE_ANY_ACCESS)


#define IOCTL_TEST3 CTL_CODE(
			FILE_DEVICE_UNKNOWN, 
			0x802, 
			METHOD_NEITHER, 
			FILE_ANY_ACCESS)


#endif
CPP文件:

#include <windows.h>
#include <stdio.h>
//使用CTL_CODE必须加入winioctl.h
#include <winioctl.h>
#include "..NT_DriverIoctls.h"

int main()
{
	HANDLE hDevice = 
		CreateFile("\\.\HelloDDK",
					GENERIC_READ | GENERIC_WRITE,
					0,		// share mode none
					NULL,	// no security
					OPEN_EXISTING,
					FILE_ATTRIBUTE_NORMAL,
					NULL );		// no template

	if (hDevice == INVALID_HANDLE_VALUE)
	{
		printf("Failed to obtain file handle to device: "
			"%s with Win32 error code: %d
",
			"MyWDMDevice", GetLastError() );
		return 1;
	}

	UCHAR InputBuffer[10];
	UCHAR OutputBuffer[10];
	//将输入缓冲区全部置成0XBB
	memset(InputBuffer,0xBB,10);
	DWORD dwOutput;
	//输入缓冲区作为输入,输出缓冲区作为输出

	BOOL bRet;
	//缓冲内存模式  IOCTL////////////////////////////////////////////////
	bRet = DeviceIoControl(hDevice, IOCTL_TEST1, InputBuffer, 10, &OutputBuffer, 10, &dwOutput, NULL);
	//InputBuffer 为输入缓冲区		OutputBuffer为接收的缓冲区
	if (bRet)
	{
		printf("Output buffer:%d bytes
",dwOutput);
		for (int i=0;i<(int)dwOutput;i++)
		{
			printf("%02X ",OutputBuffer[i]);
		}
		printf("
");
	}
	//直接内存模式  IOCTL////////////////////////////////////////////////
	bRet = DeviceIoControl(hDevice, IOCTL_TEST2, InputBuffer, 10, &OutputBuffer, 10, &dwOutput, NULL);
	if (bRet)
	{
		printf("Output buffer:%d bytes
",dwOutput);
		for (int i=0;i<(int)dwOutput;i++)
		{
			printf("%02X ",OutputBuffer[i]);
		}
		printf("
");
	}
	//其他内存模式  IOCTL////////////////////////////////////////////////
 	bRet = DeviceIoControl(hDevice, IOCTL_TEST3, InputBuffer, 10, &OutputBuffer, 10, &dwOutput, NULL);
	if (bRet)
	{
		printf("Output buffer:%d bytes
",dwOutput);
		for (int i=0;i<(int)dwOutput;i++)
		{
			printf("%02X ",OutputBuffer[i]);
		}
		printf("
");
	}

	CloseHandle(hDevice);

	return 0;
}
内核模式  显示  应用程序字符串:

#pragma PAGEDCODE
NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
								 IN PIRP pIrp)
{
	NTSTATUS status = STATUS_SUCCESS;
	KdPrint(("Enter HelloDDKDeviceIOControl
"));
	//得到当前堆栈
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
	//得到输入缓冲区大小
	ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
	//得到输出缓冲区大小
	ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
	//得到IOCTL码
	ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;

	ULONG info = 0;

	switch (code)
	{						// process request
		case IOCTL_TEST1:
		{
			KdPrint(("IOCTL_TEST1
"));
			//缓冲区方式IOCTL
			//显示输入缓冲区数据
 			UCHAR* InputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
			for (ULONG i=0;i<cbin;i++)
			{
				KdPrint(("%X
",InputBuffer[i]));
			}

			//操作输出缓冲区
			UCHAR* OutputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
			memset(OutputBuffer,0xAA,cbout);
			//设置实际操作输出缓冲区长度
 			info = cbout;
			break;
		}
		case IOCTL_TEST2:
		{
			KdPrint(("IOCTL_TEST2
"));
			//缓冲区方式IOCTL
			//显示输入缓冲区数据

			//缓冲区方式IOCTL
			//显示输入缓冲区数据
 			UCHAR* InputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
			for (ULONG i=0;i<cbin;i++)
			{
				KdPrint(("%X
",InputBuffer[i]));
			}

			//pIrp->MdlAddress为DeviceIoControl输出缓冲区地址相同
			KdPrint(("User Address:0X%08X
",MmGetMdlVirtualAddress(pIrp->MdlAddress)));

 			UCHAR* OutputBuffer = (UCHAR*)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,NormalPagePriority);
 			//InputBuffer被映射到内核模式下的内存地址,必定在0X80000000-0XFFFFFFFF之间
 			memset(OutputBuffer,0xAA,cbout);
			//设置实际操作输出缓冲区长度
 			info = cbout;
			break;
		}
		case IOCTL_TEST3:
		{
			KdPrint(("IOCTL_TEST3
"));

			//缓冲区方式IOCTL
			//显示输入缓冲区数据
 			UCHAR* UserInputBuffer = (UCHAR*)stack->Parameters.DeviceIoControl.Type3InputBuffer;
			KdPrint(("UserInputBuffer:0X%0X
",UserInputBuffer));

			//得到用户模式地址
			PVOID UserOutputBuffer = pIrp->UserBuffer;
			
			KdPrint(("UserOutputBuffer:0X%0X
",UserOutputBuffer));

			__try
			{
				KdPrint(("Enter __try block
"));

				//判断指针是否可读
				ProbeForRead(UserInputBuffer,cbin,4);
				//显示输入缓冲区内容
				for (ULONG i=0;i<cbin;i++)
				{
					KdPrint(("%X
",UserInputBuffer[i]));
				}

				//判断指针是否可写
				ProbeForWrite(UserOutputBuffer,cbout,4);

				//操作输出缓冲区
				memset(UserOutputBuffer,0xAA,cbout);

				//由于在上面引发异常,所以以后语句不会被执行!
				info = cbout;

				KdPrint(("Leave __try block
"));
			}
			__except(EXCEPTION_EXECUTE_HANDLER)
			{
				KdPrint(("Catch the exception
"));
				KdPrint(("The program will keep going
"));
				status = STATUS_UNSUCCESSFUL;
			}

 			info = cbout;
			break;
		}

		default:
			status = STATUS_INVALID_VARIANT;
	}

	// 完成IRP
	pIrp->IoStatus.Status = status;
	pIrp->IoStatus.Information = info;	// bytes xfered
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );

	KdPrint(("Leave HelloDDKDeviceIOControl
"));

	return status;
}






原文地址:https://www.cnblogs.com/zcc1414/p/3982508.html