当前位置: 代码迷 >> 综合 >> ReadFile WriteFile DO_DIRECT_IO 中的IRP操作
  详细解决方案

ReadFile WriteFile DO_DIRECT_IO 中的IRP操作

热度:76   发布时间:2023-12-15 03:44:26.0

开头很重要的一句,我就在这里载坑了,kernel_address会直接与外面的buffer映射为同一部分,那么我们可以直接操这部分内存就行了。如果想保存,那直接保存kernel_address中的内容即可。

  • kernel_address为外部内存对应的内核内存地址,实际上其实对应的为同一段物理地址
    在这里插入图片描述
    喜闻乐见的贴图一张

Driver.h

#pragma once// 用于包含ddk.h的头文件
#ifdef __cplusplus
extern "C"
{
    
#endif#include <ntddk.h>#ifdef __cplusplus
}
#endif // __cplusplus#define PAGEDCODE code_seg("PAGE") // 置于分页内存
#define LOCKEDCODE code_seg() // 置于非分页内存
#define INITCODE code_set("INIT") // 代码首次运行置于分页内存中,在使用完毕后,将其卸载#define PAGEDDATA data_seg("PAGE")
#define LOCKEDDATA data_seg()
#define INITDATA data_seg("INIT")#define arraysize(p) (sizeof(p)/sizeof((p)[0]))
#define MAX_FILE_LENGTH 1024typedef struct _DEVICE_EXTENSION
{
    PDEVICE_OBJECT pDevice;UNICODE_STRING ustrDeviceName;	// 设备名称UNICODE_STRING ustrSymlinkName;   // 符号链接名PUCHAR buffer; //缓冲区ULONG file_current_length;	//模拟的文件长度,必须小于MAX_FILE_LENGTHULONG file_max_length; // 模拟的文件最大长度
}DEVICE_EXTENSION,*PDEVICE_EXTENSION;// 函数声明
NTSTATUS CreateDevice(IN PDRIVER_OBJECT pDriverObject);
VOID HelloDDKUnload(IN PDRIVER_OBJECT pDriverObject);
NTSTATUS HelloDDKDispatchRoutin(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp);NTSTATUS HelloDDKDispatchCreate(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp);
NTSTATUS HelloDDKDispatchClose(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp);
NTSTATUS HelloDDKDispatchWrite(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp);
NTSTATUS HelloDDKDispatchRead(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp);
NTSTATUS HelloDDKQueryInformation(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp);

Driver.cpp

#include "Driver.h"/* * 函数名称:DriverEntry * 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象 * 参数列表: * pDriverObject:从I/O管理器中传进来的驱动对象 * pRegistryPath:驱动程序在注册表中的路径 * 返回值:返回初始化驱动状态 */#pragma INITCODE
extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING pRegistryPath)
{
    KdPrint(("Enter DriverEntry\n"));NTSTATUS status;UNREFERENCED_PARAMETER(pRegistryPath);  // 指明此参数未使用// 注册其他驱动调用函数入口pDriverObject->DriverUnload = HelloDDKUnload;// CreateFile会产生此IRPpDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutin;// CloseHandle会产生此IRPpDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutin;// 对设备进行WriteFile会产生此IRPpDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchWrite;// 读取设备内容,ReadFile会产生此IRPpDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKDispatchRead;// 清除工作,CloseHanle会产生此IRPpDriverObject->MajorFunction[IRP_MJ_CLEANUP] = HelloDDKDispatchRoutin;// 当向设备查询一些信息时,会调用此IRPpDriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = HelloDDKQueryInformation;// DeviceControl函数会产生此IRPpDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloDDKDispatchRoutin;// 系统关闭前,会产生此IRPpDriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = HelloDDKDispatchRoutin;// 系统内部产生的控制消息,类似于内核调用DeviceControl函数pDriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = HelloDDKDispatchRoutin;// 创建驱动设备对象status = CreateDevice(pDriverObject);KdPrint(("DriveEntry end\n"));return status;
}/* * 函数名称:CreateDevice * 功能描述:初始化设备对象 * 参数列表: * pDriverObject:从I/O管理器中传进来的驱动对象 * 返回值:返回初始化状态 */// 表示将此函数置于分页内存中,在使用完毕后,即释放
#pragma INITCODE
NTSTATUS CreateDevice(IN PDRIVER_OBJECT pDriverObject) 
{
    NTSTATUS status;PDEVICE_OBJECT pDevObj; // 一个驱动可以控制多个设备PDEVICE_EXTENSION pDevExt;// 创建设备名称UNICODE_STRING devName;RtlInitUnicodeString(&devName, L"\\Device\\MyDDKDevice"); // 字符串前加L,表示将其更换为Unicode字符// 创建对象status = IoCreateDevice(pDriverObject,sizeof(DEVICE_EXTENSION),&(UNICODE_STRING)devName,FILE_DEVICE_UNKNOWN,0, TRUE,		// 独占设备,即设备只能被一个应用程序所使用&pDevObj);if (!NT_SUCCESS(status)) {
    return status;}// 将设备设置为缓冲区设备(直接进行数据读取)pDevObj->Flags |= DO_DIRECT_IO;// 得到设备扩展pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;// 设置设备扩展为内核对象pDevExt->pDevice = pDevObj;// 设置设备扩展中的设备名称pDevExt->ustrDeviceName = devName;// 申请模拟文件的缓冲区pDevExt->buffer = (PUCHAR)ExAllocatePool(PagedPool, MAX_FILE_LENGTH);// 设置模拟文件的大小pDevExt->file_current_length = 0;pDevExt->file_max_length = MAX_FILE_LENGTH;// 创建符号链接,符号链接是为了使用户态的应用程序为可见状态,其中驱动名只是内核中可见UNICODE_STRING symLinkName;RtlInitUnicodeString(&symLinkName, L"\\??\\HelloDDK");pDevExt->ustrSymlinkName = symLinkName;// 创建符号链接status = IoCreateSymbolicLink(&symLinkName, &devName);if (!NT_SUCCESS(status)) {
    IoDeleteDevice(pDevObj);return status;}return STATUS_SUCCESS;
}/* * 函数名称:HelloDDKUnload * 功能描述:负责驱动程序的卸载操作 * 参数列表: * pDriverObject:驱动对象 * 返回值:返回状态 */#pragma PAGEDCODE
VOID HelloDDKUnload(IN PDRIVER_OBJECT pDriverObject) {
    // DisplayItsProcessName("HelloDDKUnload");PDEVICE_OBJECT pNextObj;KdPrint(("Enter DriverUnload\n"));pNextObj = pDriverObject->DeviceObject; // 由驱动对象得到设备对象while (pNextObj != NULL){
    		// 遍历设备对象,并对其进行删除工作PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pNextObj->DeviceExtension;// 删除符号链接UNICODE_STRING pLinkName = pDevExt->ustrSymlinkName;IoDeleteSymbolicLink(&pLinkName);pNextObj = pNextObj->NextDevice;IoDeleteDevice(pDevExt->pDevice);}
}/* * 函数名称:HelloDDKDispatchRoutine * 功能描述:对读IRP进行处理 * 参数列表: * pDevObj:功能设备对象 * pIrp:从I/O请求包 * 返回值:返回状态 */
#pragma PAGEDCODE
NTSTATUS HelloDDKDispatchRoutin(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) {
    KdPrint(("Enter HelloDispatchRoutine\n"));// 获取当前设备栈PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);// 建立一个字符数组与IRP类型对应起来static char* irpname[] = {
    "IRP_MJ_CREATE","IRP_MJ_CREATE_NAMED_PIPE","IRP_MJ_CLOSE","IRP_MJ_READ","IRP_MJ_WRITE","IRP_MJ_QUERY_INFORMATION","IRP_MJ_SET_INFORMATION","IRP_MJ_QUERY_EA","IRP_MJ_SET_EA","IRP_MJ_FLUSH_BUFFERS","IRP_MJ_QUERY_VOLUME_INFORMATION","IRP_MJ_SET_VOLUME_INFORMATION","IRP_MJ_DIRECTORY_CONTROL","IRP_MJ_FILE_SYSTEM_CONTROL","IRP_MJ_DEVICE_CONTROL","IRP_MJ_INTERNAL_DEVICE_CONTROL","IRP_MJ_SHUTDOWN","IRP_MJ_LOCK_CONTROL","IRP_MJ_CLEANUP","IRP_MJ_CREATE_MAILSLOT","IRP_MJ_QUERY_SECURITY","IRP_MJ_SET_SECURITY","IRP_MJ_POWER","IRP_MJ_SYSTEM_CONTROL","IRP_MJ_DEVICE_CHANGE","IRP_MJ_QUERY_QUOTA","IRP_MJ_SET_QUOTA","IRP_MJ_PNP"};UCHAR type = stack->MajorFunction;if (type >= arraysize(irpname)) {
    KdPrint(("- Unknow IRP, major type %X\n", type));}else {
    KdPrint(("\t%s\n", irpname[type]));}NTSTATUS status = STATUS_SUCCESS;// 完成IRPpIrp->IoStatus.Status = status;  // 设置IRP状态为成功pIrp->IoStatus.Information = 0;  // 设置操作字节为0,这里无实际意义IoCompleteRequest(pIrp,IO_NO_INCREMENT); // 指示完成此IRPKdPrint(("Leave HelloDDKDispatchRoutine\n"));return status;
}#pragma PAGEDCODE
NTSTATUS HelloDDKDispatchCreate(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) {
    return STATUS_SUCCESS;
}#pragma PAGEDCODE
NTSTATUS HelloDDKDispatchClose(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) {
    return STATUS_SUCCESS;
}#pragma PAGEDCODE
NTSTATUS HelloDDKDispatchWrite(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) {
    KdPrint(("Enter HelloDDKWrite\n"));PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;NTSTATUS status = STATUS_SUCCESS;PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);// 获取存储的长度ULONG ulWriteLength = (ULONG)stack->Parameters.Write.Length;// 得到锁定缓冲区的长度ULONG mdl_length = MmGetMdlByteCount(pIrp->MdlAddress);// 得到锁定缓冲区的首地址PVOID mdl_address = MmGetMdlVirtualAddress(pIrp->MdlAddress);// 得到锁定缓冲区的偏移量ULONG mdl_offset = MmGetMdlByteOffset(pIrp->MdlAddress);KdPrint(("write->mdl_address:0X%016X\n", mdl_address));KdPrint(("write->mdl_length:%d\n", mdl_length));KdPrint(("write->mdl_offset:%d\n", mdl_offset));KdPrint(("write->ulWriteLength:%d\n", ulWriteLength));if (ulWriteLength != mdl_length || ulWriteLength >= pDevExt->file_max_length) {
    // MDL的长度应该和读长度相等,否则该操作应该设为不成功pIrp->IoStatus.Information = 0;status = STATUS_UNSUCCESSFUL;}else {
    // 用MmGetSystemAddressForMdlSafe得到MDL在内核模式下的映射 PVOID kernel_address = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,NormalPagePriority);KdPrint(("write->kernel_address:0X%016X\n", kernel_address));memcpy(pDevExt->buffer, kernel_address, ulWriteLength);pDevExt->file_current_length = ulWriteLength;pIrp->IoStatus.Information = ulWriteLength;}pIrp->IoStatus.Status = status;pIrp->IoStatus.Information = ulWriteLength;IoCompleteRequest(pIrp, IO_NO_INCREMENT);KdPrint(("Leave HelloDDKWrite\n"));return STATUS_SUCCESS;
}#pragma PAGEDCODE
NTSTATUS HelloDDKDispatchRead(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) {
    KdPrint(("Enter HelloDDKRead\n"));// 得到设备的扩展PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;NTSTATUS status = STATUS_SUCCESS;// 得到当前IO堆栈PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);// 获取指定的读字节数ULONG ulReadLenth = stack->Parameters.Read.Length;KdPrint(("ulReadLength:%d\n", ulReadLenth));// 得到锁定缓冲区的长度ULONG mdl_length = MmGetMdlByteCount(pIrp->MdlAddress);// 得到锁定缓冲区的首地址PVOID mdl_address = MmGetMdlVirtualAddress(pIrp->MdlAddress);// 得到锁定缓冲区的偏移量ULONG mdl_offset = MmGetMdlByteOffset(pIrp->MdlAddress);KdPrint(("mdl_address:0X%016X\n",mdl_address));KdPrint(("mdl_length:%d\n",mdl_length));KdPrint(("mdl_offset:%d\n",mdl_offset));if (mdl_length != ulReadLenth || ulReadLenth >= pDevExt->file_max_length) {
    // MDL的长度应该和读长度相等,否则该操作应该设为不成功pIrp->IoStatus.Information = 0;status = STATUS_UNSUCCESSFUL;}else {
    // 用MmGetSystemAddressForMdlSafe得到MDL在内核模式下的映射 PVOID kernel_address = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);// 填充内存memcpy(kernel_address, pDevExt->buffer, pDevExt->file_current_length);pIrp->IoStatus.Information = ulReadLenth;}// 设置完成状态pIrp->IoStatus.Status = status;// 结束IRP请求IoCompleteRequest(pIrp, IO_NO_INCREMENT);KdPrint(("Leave HelloDDKRead\n"));return status;
}#pragma PAGEDCODE
NTSTATUS HelloDDKQueryInformation(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) {
    KdPrint(("Enter HelloDDKQueryInformation\n"));// 获取IO堆栈PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);// 获得设备扩展PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;// 得到文件信息FILE_INFORMATION_CLASS info = stack->Parameters.QueryFile.FileInformationClass;// 判断是否为标准文件信息if (info == FileStandardInformation) {
    KdPrint(("FileStandardInformation\n"));PFILE_STANDARD_INFORMATION file_info =(PFILE_STANDARD_INFORMATION)pIrp->AssociatedIrp.SystemBuffer;file_info->EndOfFile = RtlConvertLongToLargeInteger(pDevExt->file_current_length);}NTSTATUS status = STATUS_SUCCESS;// 设置IRP完成状态pIrp->IoStatus.Status = status;// 设置IRP操作字节pIrp->IoStatus.Information = stack->Parameters.QueryFile.Length;// 结束irp请求IoCompleteRequest(pIrp, IO_NO_INCREMENT);KdPrint(("Leave HelloDDKQueryInformation\n"));return status;
}

main.c

此cpp用于读写测试,为exe文件

#include <windows.h>
#include <stdio.h>
VOID WriteAndReadDriver() {
    // 测试驱动程序HANDLE hDevice = CreateFile("\\\\.\\HelloDDK",GENERIC_WRITE | GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);if (hDevice != INVALID_HANDLE_VALUE) {
    printf("Open Driver ok!\n");}else {
    printf("Open Driver faild %d!\n", GetLastError());}UCHAR buffer[10];printf("buffer->%016x\n", buffer);memset(buffer, 0Xcd, 10);ULONG ulWrite;// 对设备进行写BOOL bRet = WriteFile(hDevice, buffer, 10, &ulWrite, NULL);if (bRet) {
    printf("Write %d bytes.\n", ulWrite);for (int i = 0; i < ulWrite; i++) {
    printf("%02X ", buffer[i]);}}buffer[0] = 0xab;//SetFilePointer(hDevice, 10, NULL, FILE_BEGIN);//memset(buffer, 0Xdd, 10); 对设备进行写//bRet = WriteFile(hDevice, buffer, 10, &ulWrite, NULL);//if (bRet) {
    // printf("Write %d bytes.\n", ulWrite);//}UCHAR buffer2[10] = {
     0 };memset(buffer2, 0xff, 10);ULONG ulRead;// 对设备进行读bRet = ReadFile(hDevice, buffer2, 10, &ulRead, NULL);if (bRet) {
    printf("Read %d bytes:", ulRead);for (int i = 0; i < ulRead; i++) {
    printf("%02X ", buffer2[i]);}printf("\n");}printf("file length:%d\n", GetFileSize(hDevice, NULL));if (CloseHandle(hDevice)) {
    printf("Close ok!\n");}else {
    printf("Close FAILD %d!\n", GetLastError());}
}int main() {
    //TestDriver();WriteAndReadDriver();//ReadDriver();system("pause");return 0;
}