本文讲怎样通过向 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");