内核文件管理-IRP(三)文件读写

本文讲怎样通过向 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 函数类似,仅 IRPI/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);

下一篇:内核文件管理-IRP(四)文件遍历

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值