内核文件管理-IRP(二)文件属性查询和设置

本文讲怎样通过向 FSD 发送 IRP_MJ_QUERY_INFORMATION 消息 / IRP_MJ_SET_INFORMATION 消息的 IRP 来 查询/设置 文件属性。
上一篇:内核文件管理-IRP(一)创建或打开文件

IrpQueryInformationFile函数参数

该函数是在打开文件的基础上操作的,用于查询文件的信息,上一篇 内核文件管理-IRP(一)创建或打开文件 中实现的 IrpCreateFile 函数成功打开文件后返回的 文件句柄 ,这里将作为参数传入 IrpQueryInformationFile 函数。

NTSTATUS IrpQueryInformationFile(
	IN	PFILE_OBJECT pFileObject,						// 文件句柄
	OUT PIO_STATUS_BLOCK IoStatusBlock,					// 用于返回最终完成的状态和其他请求操作的信息
	OUT	PVOID FileInformation,							// 返回的文件信息
	IN	ULONG Length,									// FileInformation结构的长度
	IN	FILE_INFORMATION_CLASS FileInformationClass);	// FileInformatino的类型

IrpQueryInformationFile实现

变量定义略,具体参见源代码

1.判断传入的参数,然后获得设备对象

if (NULL == pFileObject)
	{
		return STATUS_UNSUCCESSFUL;
	}
	if (NULL == pFileObject->Vpb)
	{
		return STATUS_UNSUCCESSFUL;
	}
	pDevObj = pFileObject->Vpb->DeviceObject;	// 由文件对象中的VPB得到
	if (NULL == pDevObj)
	{
		return STATUS_UNSUCCESSFUL;
	}

2.创建IRP和等待IRP处理完成的事件

根据设备对象的栈大小创建IRP,然后创建事件用于通知IRP的处理完成。

	pIRP = IoAllocateIrp(pDevObj->StackSize, FALSE);
	if (NULL == pIRP)
	{
		return STATUS_UNSUCCESSFUL;
	}
	KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);

3.设置IRP

	RtlZeroMemory(FileInformation, Length);
	pIRP->UserEvent = &kEvent;
	pIRP->UserIosb = IoStatusBlock;
	pIRP->AssociatedIrp.SystemBuffer = FileInformation;
	pIRP->RequestorMode = KernelMode;
	pIRP->Tail.Overlay.Thread = PsGetCurrentThread();
	pIRP->Tail.Overlay.OriginalFileObject = pFileObject;

4.获取下一个IRP的IO_STACK_LOCATION并设置

这里设置 IRP_MJ_QUERY_INFORMATION 等信息。

	pIoStackLocation = IoGetNextIrpStackLocation(pIRP);
	pIoStackLocation->MajorFunction = IRP_MJ_QUERY_INFORMATION;
	pIoStackLocation->DeviceObject = pDevObj;
	pIoStackLocation->FileObject = pFileObject;
	pIoStackLocation->Parameters.QueryFile.Length = Length;
	pIoStackLocation->Parameters.QueryFile.FileInformationClass = FileInformationClass;

5.设置完成实例

	IoSetCompletionRoutine(pIRP, CompleteRoutine, NULL, TRUE, TRUE, TRUE);

CompleteRoutine 函数与上一篇《内核文件管理-IRP(一)创建或打开文件》中的 CompleteRoutine 函数相同。

6.发送IRP,等待处理完成并返回结果

	// 发送IRP
	status = IoCallDriver(pDevObj, pIRP);
	// 等待IRP处理完成
	if (STATUS_PENDING == status)
	{
		KeWaitForSingleObject(&kEvent, Executive, KernelMode, FALSE, NULL);
	}
	// 返回执行结果
	return IoStatusBlock->Status;

成功的话,要求的文件信息将保存到传入参数 PVOID FileInformation 中。

IrpSetInformationFile函数参数

该函数也是在打开文件的基础上操作的,用于设置文件属性。其参数和实现基本与IrpQueryInformationFile函数相同,区别仅仅在于 IRP下一个IRP的IO_STACK_LOCATION 的设置,本文仅展示该设置,不再多说。

	NTSTATUS IrpSetInformationFile(
	IN	PFILE_OBJECT pFileObject,						// 文件句柄
	OUT PIO_STATUS_BLOCK IoStatusBlock,					// 用于返回最终完成的状态和其他请求操作的信息
	IN	PVOID FileInformation,							// 设置的文件信息
	IN	ULONG Length,									// FileInformation结构的长度
	IN	FILE_INFORMATION_CLASS FileInformationClass);	// FileInformatino的类型

IrpSetInformationFile设置

变量定义略,具体参见源代码

IRP设置

	pIRP->UserEvent = &kEvent;
	pIRP->UserIosb = IoStatusBlock;
	pIRP->AssociatedIrp.SystemBuffer = FileInformation;	// 这里FileInformation是传入的,所以没有RtlZeroMemory
	pIRP->RequestorMode = KernelMode;
	pIRP->Tail.Overlay.Thread = PsGetCurrentThread();
	pIRP->Tail.Overlay.OriginalFileObject = pFileObject;

下一个IRP的IO_STACK_LOCATION 的设置

这里不同设置为 IRP_MJ_SET_INFORMATION ,以及设置的参数为 SetFile 。

	pIoStackLocation = IoGetNextIrpStackLocation(pIRP);
	pIoStackLocation->MajorFunction = IRP_MJ_SET_INFORMATION;
	pIoStackLocation->DeviceObject = pDevObj;
	pIoStackLocation->FileObject = pFileObject;
	pIoStackLocation->Parameters.SetFile.Length = Length;
	pIoStackLocation->Parameters.SetFile.FileInformationClass = FileInformationClass;

例子

以下代码获取了文件 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_READ, &ustrOpenFile,
			&iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ,
			FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
		if (!NT_SUCCESS(status))
		{
			DbgPrint("[ERROR]   IrpCreateFile: 打开文件\n");
			return;
		}
		DbgPrint("[SUCCESS] IrpCreateFile: 打开文件\n");
		FILE_STANDARD_INFORMATION fsi = { 0 };
		status = IrpQueryInformationFile(hFile, &iosb, &fsi, sizeof(fsi), FileStandardInformation);
		if (!NT_SUCCESS(status))
		{
			DbgPrint("[ERROR]   IrpQueryInformationFile: 获取文件信息\n");
			ObDereferenceObject(hFile);
			return;
		}
		ObDereferenceObject(hFile);
		DbgPrint("[SUCCESS] IrpQueryInformationFile: 文件大小 %I64d\n", fsi.EndOfFile.QuadPart);

以下代码设置了文件 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_READ | GENERIC_WRITE, &ustrOpenFile,
			&iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
			FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
		if (!NT_SUCCESS(status))
		{
			DbgPrint("[ERROR]   IrpCreateFile: 打开文件\n");
			return;
		}
		DbgPrint("[SUCCESS] IrpCreateFile: 打开文件\n");
		FILE_BASIC_INFORMATION fileBaseInfo = { 0 };
		RtlZeroMemory(&fileBaseInfo, sizeof(fileBaseInfo));
		fileBaseInfo.FileAttributes = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
		status = IrpSetInformationFile(hFile, &iosb, &fileBaseInfo, sizeof(fileBaseInfo), FileBasicInformation);
		if (!NT_SUCCESS(status))
		{
			DbgPrint("[ERROR]   IrpSetInformationFile: 设置文件属性\n");
			ObDereferenceObject(hFile);
			return;
		}
		ObDereferenceObject(hFile);
		DbgPrint("[SUCCESS] IrpSetInformationFile: 设置文件属性\n");

下一篇:内核文件管理-IRP(三)文件读写

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值