本文讲怎样通过向 FSD 发送 IRP_MJ_READ 消息 / IRP_MJ_WRITE 消息的 IRP 来 读/写 文件内容。
上一篇:内核文件管理-IRP(二)文件属性查询和设置
IrpReadFile函数参数
该函数是在 IrpCreateFile函数 打开文件的基础上操作的,用于读取文件。
NTSTATUS IrpReadFile(
IN PFILE_OBJECT pFileObject, // 文件句柄
OUT PIO_STATUS_BLOCK IoStatusBlock, // 用于返回最终完成的状态和其他请求操作的信息
OUT PVOID Buffer, // 输出缓冲区
IN ULONG BufferLength, // 缓冲区长度
IN PLARGE_INTEGER ByteOffset OPTIONAL); // 读取偏移位置
IrpReadFile实现
变量定义略,具体参见源代码。
IrpReadFile 实现与 IrpQueryInformationFile 函数类似,仅 IRP 和 I/O堆栈 设置不同,以及在判断参数完成以后,需要根据 ByteOffset 参数调整读取的偏移,在内存读写上使用了MDL(MDL需要在完成实例CompleteRoutine中释放)。
调整文件偏移位置
if (NULL == ByteOffset) { if (0 == (FO_SYNCHRONOUS_IO & pFileObject->Flags)) { return STATUS_INVALID_PARAMETER; } ByteOffset = &pFileObject->CurrentByteOffset; }
IRP设置
RtlZeroMemory(Buffer, BufferLength); pIRP->MdlAddress = MmCreateMdl(NULL, Buffer, BufferLength); // 通过MDL修改内存 if (NULL == pIRP->MdlAddress) { IoFreeIrp(pIRP); return STATUS_INSUFFICIENT_RESOURCES; } MmBuildMdlForNonPagedPool(pIRP->MdlAddress); pIRP->UserEvent = &kEvent; pIRP->UserIosb = IoStatusBlock; pIRP->Flags = IRP_READ_OPERATION; pIRP->RequestorMode = KernelMode; pIRP->Tail.Overlay.Thread = PsGetCurrentThread(); pIRP->Tail.Overlay.OriginalFileObject = pFileObject;
获取下一个IRP的IO_STACK_LOCATION并设置
IRP_MJ_READ消息,Read的参数等基本信息设置。
pIoStackLocation = IoGetNextIrpStackLocation(pIRP); pIoStackLocation->MajorFunction = IRP_MJ_READ; pIoStackLocation->MinorFunction = IRP_MN_NORMAL; pIoStackLocation->DeviceObject = pDevObj; pIoStackLocation->FileObject = pFileObject; pIoStackLocation->Parameters.Read.Length = BufferLength; pIoStackLocation->Parameters.Read.ByteOffset = *ByteOffset;
CompleteRoutine中添加的内容:
在释放IRP前释放MDL:
if (pIRP->MdlAddress) { IoFreeMdl(pIRP->MdlAddress); pIRP->MdlAddress = NULL; }
IrpWriteFile函数参数
该函数也是在 IrpCreateFile函数 打开文件的基础上操作的,用于写入文件,参数及实现都与 IrpReadFile 相似。
NTSTATUS IrpWriteFile(
IN PFILE_OBJECT pFileObject, // 文件句柄
OUT PIO_STATUS_BLOCK IoStatusBlock, // 用于返回最终完成的状态和其他请求操作的信息
IN PVOID Buffer, // 输入缓冲区
IN ULONG BufferLength, // 缓冲区长度
IN PLARGE_INTEGER ByteOffset OPTIONAL); // 写入偏移位置
IrpWriteFile设置
变量定义略,具体参见源代码。
IRP设置
pIRP->MdlAddress = MmCreateMdl(NULL, Buffer, BufferLength); if (NULL == pIRP->MdlAddress) { IoFreeIrp(pIRP); return STATUS_INSUFFICIENT_RESOURCES; } MmBuildMdlForNonPagedPool(pIRP->MdlAddress); pIRP->UserEvent = &kEvent; pIRP->UserIosb = IoStatusBlock; pIRP->Flags = IRP_WRITE_OPERATION; pIRP->RequestorMode = KernelMode; pIRP->Tail.Overlay.Thread = PsGetCurrentThread(); pIRP->Tail.Overlay.OriginalFileObject = pFileObject;
获取下一个IRP的IO_STACK_LOCATION并设置
IRP_MJ_WRITE消息,Write的参数等基本信息设置。
pIoStackLocation = IoGetNextIrpStackLocation(pIRP); pIoStackLocation->MajorFunction = IRP_MJ_WRITE; pIoStackLocation->MinorFunction = IRP_MN_NORMAL; pIoStackLocation->DeviceObject = pDevObj; pIoStackLocation->FileObject = pFileObject; pIoStackLocation->Parameters.Write.Length = BufferLength; pIoStackLocation->Parameters.Write.ByteOffset = *ByteOffset;
例子
以下代码将 “Hello!” 字符串写入文件 C:\Hello\test.txt 中:
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING ustrOpenFile;
RtlInitUnicodeString(&ustrOpenFile, L"C:\\Hello\\test.txt");
PFILE_OBJECT hFile = NULL;
IO_STATUS_BLOCK iosb = { 0 };
status = IrpCreateFile(&hFile, GENERIC_WRITE, &ustrOpenFile,
&iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN, FILE_NO_INTERMEDIATE_BUFFERING | FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (!NT_SUCCESS(status))
{
DbgPrint("[ERROR] IrpCreateFile: 打开文件\n");
return;
}
DbgPrint("[SUCCESS] IrpCreateFile: 打开文件\n");
RtlZeroMemory(&iosb, sizeof(iosb));
LARGE_INTEGER liWriteOffset = { 0 };
UCHAR szWriteData[256] = "Hello!";
ULONG ulWriteDataLength = 1 + strlen(szWriteData);
status = IrpWriteFile(hFile, &iosb, szWriteData, ulWriteDataLength, &liWriteOffset); // 写入
ulWriteDataLength = iosb.Information; // 实际写入字节数
if (!NT_SUCCESS(status))
{
ObDereferenceObject(hFile);
DbgPrint("[ERROR] IrpWriteFile: 写入文件\n");
return;
}
ObDereferenceObject(hFile);
DbgPrint("[SUCCESS] IrpWriteFile: 大小 %dB\n", ulWriteDataLength);
以下代码将读取文件 C:\Hello\test.txt 的内容(这里读缓冲大小为256B):
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING ustrOpenFile;
RtlInitUnicodeString(&ustrOpenFile, L"C:\\Hello\\test.txt");
PFILE_OBJECT hFile = NULL;
IO_STATUS_BLOCK iosb = { 0 };
UCHAR szReadData[256] = { 0 };
ULONG ulReadDataSize = 256;
status = IrpCreateFile(&hFile, GENERIC_READ, &ustrOpenFile,
&iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN, FILE_NO_INTERMEDIATE_BUFFERING | FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (!NT_SUCCESS(status))
{
DbgPrint("[ERROR] IrpCreateFile: 打开文件\n");
return;
}
DbgPrint("[SUCCESS] IrpCreateFile: 打开文件\n");
RtlZeroMemory(&iosb, sizeof(iosb));
LARGE_INTEGER liReadOffset = { 0 };
status = IrpReadFile(hFile, &iosb, szReadData, ulReadDataSize, &liReadOffset); // 读取
ulReadDataSize = iosb.Information; // 实际读取字节数
if (!NT_SUCCESS(status))
{
ObDereferenceObject(hFile);
DbgPrint("[ERROR] IrpReadFile: 读取文件\n");
return;
}
ObDereferenceObject(hFile);
DbgPrint("[SUCCESS] IrpReadFile: 大小 %dB [%s]\n", ulReadDataSize, szReadData);