ring3通过METHOD_BUFFERED、METHOD_IN_DIRECT两种常用方式和ring0级交互读文件测试
2014-08-28 00:15
375 查看
为了熟悉ring3和ring0交互过程,写了个简单的程序测试一下,以便加深印象。
本文通过测试METHOD_BUFFERED、METHOD_IN_DIRECT方式读某磁盘下固定的文件,关于ring0和ring3通信方式具体见如下链接
http://book.51cto.com/art/201107/275240.htm
具体代码如下:
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; }
相关文章推荐
- 搭建与测试Spring的开发环境_容器常用的两种方式
- 文件读写的常用的两种方式
- 详解常用测试机器(服务)是否可用的两种方式
- 两种常用文件分享方式 - 网络硬盘快速分享, 点对点的文件共享 BitTorrent Sync
- 常用的两种ajax上传文件的方式
- Oracle中的两种验证方式:操作系统验证和密码文件验证,通过操作系统验证的方式解决客户端登录不了数据的问题
- Perl读取文件的两种常用方式
- Java中在特定区间产生随机数 (2009-03-26 13:31:49)转载▼ 标签: 杂谈 生成指定范围内的随机数 这个是最常用的技术之一。程序员希望通过随机数的方式来处理众多的业务逻辑,测试
- 常用的两种ajax上传文件的方式
- java读取Properties文件常用两种方式
- 最新隐藏进程 RING3实现方式:hook ZwQuerySystemInformation 隐藏进程 在XP里测试通过
- 移动端常用的数据交互格式有xml和json两种方式
- linux下通过编写测试程序的方式来确认arm-linux-gnueabihf-gcc-4.6lib和.h文件的安装位置,为复制libnl做准备
- java 实现BufferedImage和ImageReader两种方式获取图片宽高、判断图片类型、获取图片大小工具类代码以及测试响应结果
- 程序使用 HTTP 协议和服务器交互主要是进行数据的提交,通常数据的提交是通过 GET 和 POST 两种方式来完成
- Servlet简介以及通过配置文件和注解两种方式部署Servlet
- axis2通过services.xml配置文件发布的两种方式
- xml文件解析类及Android项目中常用到的两种获取xml文件方式
- springmvc常用注、上传文件以及后台返回前台数据的两种方式
- vc++读取文件属性的详细信息描述 通过读取QQ的注册表和EXE路径两种方式