为了熟悉ring3和ring0交互过程,写了个简单的程序测试一下,以便加深印象。
本文通过测试METHOD_BUFFERED、METHOD_IN_DIRECT方式读某磁盘下固定的文件,关于ring0和ring3通信方式具体见如下链接
http://book.51cto.com/art/201107/275240.htm
具体代码如下:
ring3:
#include <Windows.h>
#include <winioctl.h>
#include <stdio.h>
#define BUFFERSIZE 1024
//两种读写方式
#define IOCTL_DO_BUFFER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_IN_DIRECT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
//
//
void Usage(char *proc)
{
printf(
"%s -b // buffer io\n"
"%s -d // direct io\n",
proc, proc
);
}
int main(int argc, char* argv[])
{
if(argc != 2)
{
Usage(argv[0]);
return 0;
}
char OutBufer[BUFFERSIZE];
bool ret = true;
DWORD dwLength = 0; //实际读到的文件大小
HANDLE hDevice = CreateFile(
"\\\\.\\KeReadSL",
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_SYSTEM,
NULL);
if(hDevice == INVALID_HANDLE_VALUE)
{
printf("Failed to open device ---- errorcode = %d ...\n",GetLastError());
return 0;
}
if(strcmp(argv[1], "-b") == 0)
{
printf("Read File by Buffer Io way...\n");
ret = DeviceIoControl(hDevice,
IOCTL_DO_BUFFER,
NULL,
0,
OutBufer,
BUFFERSIZE,
&dwLength,
NULL);
}
else if (strcmp(argv[1], "-d") == 0)
{
printf("Read File by Direct Io way...\n");
ret = DeviceIoControl(hDevice,
IOCTL_IN_DIRECT,
NULL,
0,
OutBufer,
BUFFERSIZE,
&dwLength,
NULL);
}
else
{
Usage(argv[0]);
ret = false;
}
if(ret)
{
OutBufer[dwLength] = '\0';
printf("Congratulation!!!\nReadData: %s\n",OutBufer);
}
CloseHandle(hDevice);
return 0;
}
ring0
#include <ntddk.h>
#define IOCTL_DO_BUFFER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_IN_DIRECT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
typedef struct _DEVICE_EXTENSION
{
PDEVICE_OBJECT pDevice;
UNICODE_STRING ustrDeviceName; //设备名称
UNICODE_STRING ustrSymlinkName; //符号链接名称
}DEVICE_EXTENSION, *PDEVICE_EXTENSION;
//
// 读文件(为了方便,测试读取c盘下一个小的test.txt文件)
ULONG KeReadFileData(UCHAR* OutputBuffer, ULONG BufferSize, ULONG* ReadSize)
{
OBJECT_ATTRIBUTES objectAtrtributes;
IO_STATUS_BLOCK iostatus;
HANDLE hFile;
//初始化文件路径
UNICODE_STRING ustrFilePath;
RtlInitUnicodeString(&ustrFilePath, L"\\??\\C:\\test.txt");
InitializeObjectAttributes(&objectAtrtributes, &ustrFilePath, OBJ_CASE_INSENSITIVE, NULL, NULL);
//打开文件
NTSTATUS zwStatus = ZwCreateFile(&hFile,
GENERIC_READ,
&objectAtrtributes,
&iostatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if(!NT_SUCCESS(zwStatus))
{
KdPrint(("The file is not exist!\n"));
return 0;
}
//获取文件长度
FILE_STANDARD_INFORMATION fsi;
zwStatus = ZwQueryInformationFile(hFile,
&iostatus,
&fsi,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation);
if(!NT_SUCCESS(zwStatus))
{
KdPrint(("Failed to ZwQueryInformationFile ...\n"));
ZwClose(hFile);
return 0;
}
ULONG DataSizeReaded = BufferSize < fsi.EndOfFile.QuadPart ? BufferSize : fsi.EndOfFile.QuadPart; //实际读取文件的大小
//读取文件
zwStatus =ZwReadFile(hFile,
NULL,
NULL,
NULL,
&iostatus,
OutputBuffer,
DataSizeReaded,
NULL,
NULL
);
if(!NT_SUCCESS(zwStatus))
{
KdPrint(("Failed to ZwReadFile ...\n"));
ZwClose(hFile);
return 0;
}
KdPrint(("The program really read %d byutes ...\n",iostatus.Information));
*ReadSize = iostatus.Information;
ZwClose(hFile);
return 1;
}
//
//创建设备
NTSTATUS CreateDevice(PDRIVER_OBJECT pDriverObject, UNICODE_STRING devname, UNICODE_STRING symLinkName)
{
NTSTATUS status;
PDEVICE_OBJECT pDevObj;
PDEVICE_EXTENSION pDevExt;
//创建设备
status = IoCreateDevice(pDriverObject,
sizeof(DEVICE_EXTENSION),
&devname,
FILE_DEVICE_UNKNOWN,
0,
TRUE,
&pDevObj);
if(!NT_SUCCESS(status))
return status;
pDevObj->Flags |= DO_BUFFERED_IO;
pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
pDevExt->pDevice = pDevObj;
pDevExt->ustrDeviceName = devname;
pDevExt->ustrSymlinkName = symLinkName;
KdPrint(("devname = %wZ\nsymbollink = %wZ\n",&devname, &symLinkName));
//创建设备链接
status = IoCreateSymbolicLink(&symLinkName, &devname);
if(!NT_SUCCESS(status))
{
KdPrint(("Failed to IoCreateSymbolicLink and delete DeviceObject --- errorcode = %d ...\n",status));
IoDeleteDevice(pDevObj);
return status;
}
return status;
}
//卸载驱动
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
PDEVICE_OBJECT pNextObj;
KdPrint(("Enter DriverUnload...\n"));
pNextObj = pDriverObject->DeviceObject;
//循环遍历删除所有该驱动上的设备
while(pNextObj != NULL)
{
//设备的名称和链接名称均在扩展结构中存储
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pNextObj->DeviceExtension;
//删除符号链接
UNICODE_STRING LinkName = pDevExt->ustrSymlinkName;
IoDeleteSymbolicLink(&LinkName);
pNextObj = pNextObj->NextDevice;
IoDeleteDevice(pDevExt->pDevice);
}
}
//处理消息
NTSTATUS DeviceIoControlDispatch(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
NTSTATUS status = STATUS_SUCCESS;
KdPrint(("Enter DeviceIoControlDispatch ...\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 ReadSize = 0;
//判断文件操作方式
switch(code)
{
case IOCTL_DO_BUFFER: //缓冲区方式操作仅进行读文件测试)
{
UCHAR* OutputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
if(!KeReadFileData(OutputBuffer, cbout, &ReadSize))
status = STATUS_UNSUCCESSFUL;
break;
}
case IOCTL_IN_DIRECT: //直接文件操作
{
//将缓冲区映射到内核模式下地址
UCHAR* OutputBuffer = (UCHAR*)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);
if(!KeReadFileData(OutputBuffer, cbout, &ReadSize))
status = STATUS_UNSUCCESSFUL;
break;
}
default:
{
status = STATUS_INVALID_VARIANT;
}
}
//设置IRP的完成状态
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = ReadSize;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
KdPrint(("Leave DeviceIoControlDispatch ...\n"));
return status;
}
//IRP请求处理函数
NTSTATUS MyDispatchFunction(PDEVICE_OBJECT device, PIRP irp)
{
//获得当前IRP调用的栈空间
PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(irp);
NTSTATUS status = STATUS_INVALID_PARAMETER;
//处理各种请求
switch(irpsp->MajorFunction)
{
case IRP_MJ_CREATE: //此IRP需做简单处理,否则CreateFile打开设备链接出错
{
//简单返回一个IRP成功三部曲
irp->IoStatus.Information = 0;
irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(irp,IO_NO_INCREMENT);
//应用层,打开设备后 打印此字符串,仅为测试
DbgPrint("congratulations gay,open device");
status = irp->IoStatus.Status;
break;
}
case IRP_MJ_CLOSE:
{
irp->IoStatus.Information = 0;
irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(irp,IO_NO_INCREMENT);
//应用层,打开设备后 打印此字符串,仅为测试
DbgPrint("congratulations gay,close device");
status = irp->IoStatus.Status;
break;
}
case IRP_MJ_READ:
{
break;
}
default:
{
DbgPrint("unknow request!!!");
break;
}
}
return status;
}
NTSTATUS
DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegistryPath)
{
DbgPrint("Enter DriverEntry\n");
// KdPrint(("Enter DriverEntry\n"));
NTSTATUS status;
//设置派遣函数
for (int i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
pDriverObject->MajorFunction[i] = MyDispatchFunction;
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceIoControlDispatch;
pDriverObject->DriverUnload = DriverUnload;
//创建设备和链接
UNICODE_STRING ustrDevName, ustrSymbolicName;
RtlInitUnicodeString(&ustrDevName, L"\\Device\\KeRead");
RtlInitUnicodeString(&ustrSymbolicName, L"\\DosDevices\\KeReadSL");
status = CreateDevice(pDriverObject, ustrDevName, ustrSymbolicName);
if(!NT_SUCCESS(status))
{
KdPrint(("Failed to Create Device ...\n"));
return STATUS_UNSUCCESSFUL;
}
KdPrint(("Exit DriverEntry\n"));
return STATUS_SUCCESS;
}