除了 读设备和 写设备 外 还可以有一个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) #endifCPP文件:
#include <windows.h> #include <stdio.h> //使用CTL_CODE必须加入winioctl.h #include <winioctl.h> #include "..\NT_Driver\Ioctls.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\n", "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\n",dwOutput); for (int i=0;i<(int)dwOutput;i++) { printf("%02X ",OutputBuffer[i]); } printf("\n"); } //直接内存模式 IOCTL//////////////////////////////////////////////// bRet = DeviceIoControl(hDevice, IOCTL_TEST2, InputBuffer, 10, &OutputBuffer, 10, &dwOutput, NULL); if (bRet) { printf("Output buffer:%d bytes\n",dwOutput); for (int i=0;i<(int)dwOutput;i++) { printf("%02X ",OutputBuffer[i]); } printf("\n"); } //其他内存模式 IOCTL//////////////////////////////////////////////// bRet = DeviceIoControl(hDevice, IOCTL_TEST3, InputBuffer, 10, &OutputBuffer, 10, &dwOutput, NULL); if (bRet) { printf("Output buffer:%d bytes\n",dwOutput); for (int i=0;i<(int)dwOutput;i++) { printf("%02X ",OutputBuffer[i]); } printf("\n"); } CloseHandle(hDevice); return 0; }内核模式 显示 应用程序字符串:
#pragma PAGEDCODE NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { NTSTATUS status = STATUS_SUCCESS; KdPrint(("Enter HelloDDKDeviceIOControl\n")); //得到当前堆栈 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\n")); //缓冲区方式IOCTL //显示输入缓冲区数据 UCHAR* InputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer; for (ULONG i=0;i<cbin;i++) { KdPrint(("%X\n",InputBuffer[i])); } //操作输出缓冲区 UCHAR* OutputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer; memset(OutputBuffer,0xAA,cbout); //设置实际操作输出缓冲区长度 info = cbout; break; } case IOCTL_TEST2: { KdPrint(("IOCTL_TEST2\n")); //缓冲区方式IOCTL //显示输入缓冲区数据 //缓冲区方式IOCTL //显示输入缓冲区数据 UCHAR* InputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer; for (ULONG i=0;i<cbin;i++) { KdPrint(("%X\n",InputBuffer[i])); } //pIrp->MdlAddress为DeviceIoControl输出缓冲区地址相同 KdPrint(("User Address:0X%08X\n",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\n")); //缓冲区方式IOCTL //显示输入缓冲区数据 UCHAR* UserInputBuffer = (UCHAR*)stack->Parameters.DeviceIoControl.Type3InputBuffer; KdPrint(("UserInputBuffer:0X%0X\n",UserInputBuffer)); //得到用户模式地址 PVOID UserOutputBuffer = pIrp->UserBuffer; KdPrint(("UserOutputBuffer:0X%0X\n",UserOutputBuffer)); __try { KdPrint(("Enter __try block\n")); //判断指针是否可读 ProbeForRead(UserInputBuffer,cbin,4); //显示输入缓冲区内容 for (ULONG i=0;i<cbin;i++) { KdPrint(("%X\n",UserInputBuffer[i])); } //判断指针是否可写 ProbeForWrite(UserOutputBuffer,cbout,4); //操作输出缓冲区 memset(UserOutputBuffer,0xAA,cbout); //由于在上面引发异常,所以以后语句不会被执行! info = cbout; KdPrint(("Leave __try block\n")); } __except(EXCEPTION_EXECUTE_HANDLER) { KdPrint(("Catch the exception\n")); KdPrint(("The program will keep going\n")); 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\n")); return status; }