驱动开发中,文件操作是一个至关重要的环节。尽管在Windows系统中,“万物皆文件”的概念并不像在Linux中那样普遍,但文件操作仍然扮演着关键角色。例如,日记操作、强制删除文件等操作都离不开对文件系统的深入理解和操作能力。
通过亲自动手编写代码,可以有效提高自己的驱动开发水平。这不仅有助于加深对操作系统底层机制的理解,还能锻炼解决实际问题的能力。
文件定义:file.h
#pragma once
#include <ntifs.h>
#include "struct.h"
#include "Logging.h"
BOOLEAN MyFileExists(M_L ustrFilePath);
BOOLEAN MyCreateFile(M_L ustrFilePath);
BOOLEAN MyCreateFileFolder(M_L ustrFileFolderPath);
BOOLEAN MyDeleteFileOrFileFolder(M_L ustrFileName);
NTSTATUS WriteResponseCreate(UNICODE_STRING filePath);
NTSTATUS WriteResponseOpen(UNICODE_STRING filePath, PHANDLE fileHandle);
NTSTATUS WriteResponse(UNICODE_STRING response, HANDLE fileHandle);
NTSTATUS WriteResponseAppend(UNICODE_STRING response, HANDLE fileHandle);
NTSTATUS WriteResponseExists(UNICODE_STRING filePath, PBOOLEAN exists);
NTSTATUS WriteResponseDelete(UNICODE_STRING filePath);
NTSTATUS RetOpenFileHandle(UNICODE_STRING uDelFileName, PHANDLE pFileHandle);
NTSTATUS CallBackIrpCompleteionProc(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
NTSTATUS PassFileattribute(PFILE_OBJECT pFileObj);
NTSTATUS FsDeleteFile(PFILE_OBJECT pFileObj);
NTSTATUS IrpDeleteFileRun(UNICODE_STRING uDelFileName);
中间代码是我重写了一遍上面的代码使其更"好"用了一些,一般我们使用上面的,但是有一些文件操作可以看我的第一篇Windows用户层使用指令操作内核程序执行指令! (1) 日记文件,下面的代码暂时废弃,我在虚拟机中使用强删文件(IrpDeleteFileRun)时会导致不明错误:在资源管理器(explorer.exe)文件删了一刷新就会重新出现,在CMD中会直接显示拒绝访问
file.cpp
#include "file.h"
BOOLEAN MyFileExists(M_L ustrFilePath)
{
NTSTATUS status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES objectAttributes = { 0 };
IO_STATUS_BLOCK iosb = { 0 };
HANDLE hFile = NULL;
UNICODE_STRING ustrFilePathTmp;
RtlInitUnicodeString(&ustrFilePathTmp, ustrFilePath);
// 初始化对象属性结构体
InitializeObjectAttributes(&objectAttributes, &ustrFilePathTmp, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
// 打开文件
status = ZwOpenFile(&hFile, FILE_READ_ATTRIBUTES, &objectAttributes, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS(status))
{
return FALSE;
}
// 关闭句柄
ZwClose(hFile);
return TRUE;
}
BOOLEAN MyCreateFile(M_L ustrFilePath)
{
HANDLE hFile = NULL;
OBJECT_ATTRIBUTES objectAttributes = { 0 };
IO_STATUS_BLOCK iosb = { 0 };
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING ustrFilePathTmp;
RtlInitUnicodeString(&ustrFilePathTmp, ustrFilePath);
// 初始化对象属性结构体 FILE_SYNCHRONOUS_IO_NONALERT
InitializeObjectAttributes(&objectAttributes, &ustrFilePathTmp, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
// 创建文件
status = ZwCreateFile(&hFile, GENERIC_READ, &objectAttributes, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (!NT_SUCCESS(status))
{
return FALSE;
}
// 关闭句柄
ZwClose(hFile);
return TRUE;
}
BOOLEAN MyCreateFileFolder(M_L ustrFileFolderPath)
{
HANDLE hFile = NULL;
OBJECT_ATTRIBUTES objectAttributes = { 0 };
IO_STATUS_BLOCK iosb = { 0 };
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING ustrFileFolderPathTmp;
RtlInitUnicodeString(&ustrFileFolderPathTmp, ustrFileFolderPath);
// 初始化对象属性结构体
InitializeObjectAttributes(&objectAttributes, &ustrFileFolderPathTmp, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
// 创建目录 FILE_DIRECTORY_FILE
status = ZwCreateFile(&hFile, GENERIC_READ, &objectAttributes, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_CREATE, FILE_DIRECTORY_FILE, NULL, 0);
if (!NT_SUCCESS(status))
{
return FALSE;
}
// 关闭句柄
ZwClose(hFile);
return TRUE;
}
BOOLEAN MyDeleteFileOrFileFolder(M_L ustrFileName)
{
NTSTATUS status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES objectAttributes = { 0 };
UNICODE_STRING ustrFileNameTmp;
RtlInitUnicodeString(&ustrFileNameTmp, ustrFileName);
// 初始化属性
InitializeObjectAttributes(&objectAttributes, &ustrFileNameTmp, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
// 执行删除操作
status = ZwDeleteFile(&objectAttributes);
if (!NT_SUCCESS(status))
{
return FALSE;
}
return TRUE;
}
NTSTATUS WriteResponseCreate(UNICODE_STRING filePath)
{
OBJECT_ATTRIBUTES objectAttributes;
IO_STATUS_BLOCK ioStatusBlock;
NTSTATUS status;
HANDLE fileHandle = NULL;
InitializeObjectAttributes(&objectAttributes, &filePath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwCreateFile(&fileHandle, FILE_APPEND_DATA | SYNCHRONIZE, &objectAttributes, &ioStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (status != STATUS_SUCCESS) {
WriteLog("[LyKernelService] Failed to create file %wZ, status = 0x%x\n", filePath, status);
return status;
}
if (fileHandle == NULL) {
WriteLog("[LyKernelService] Failed to open file %wZ\n", filePath);
return STATUS_INVALID_HANDLE;
}
return STATUS_SUCCESS;
}
NTSTATUS WriteResponseOpen(UNICODE_STRING filePath, PHANDLE fileHandle)
{
OBJECT_ATTRIBUTES objAttr;
InitializeObjectAttributes(&objAttr, &filePath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
IO_STATUS_BLOCK ioStatus;
NTSTATUS status = STATUS_SUCCESS;
HANDLE fileHandleTmp = NULL;
status = ZwCreateFile(&fileHandleTmp, FILE_APPEND_DATA | SYNCHRONIZE, & objAttr, & ioStatus, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (status != STATUS_SUCCESS) {
WriteLog("[LyKernelService] Failed to open file %wZ, status = 0x%x\n", filePath, status);
return status;
}
if (fileHandleTmp == NULL) {
WriteLog("[LyKernelService] Failed to open file %wZ\n", filePath);
return STATUS_INVALID_HANDLE;
}
*fileHandle = fileHandleTmp;
return STATUS_SUCCESS;
}
NTSTATUS WriteResponse(UNICODE_STRING response, HANDLE fileHandle)
{
IO_STATUS_BLOCK ioStatusBlock;
NTSTATUS status;
status = ZwWriteFile(fileHandle, NULL, NULL, NULL, &ioStatusBlock, response.Buffer, response.Length / 2, NULL, NULL);
if (status != STATUS_SUCCESS) {
WriteLog("[LyKernelService] Failed to write to file, status = 0x%x\n", status);
}
ZwClose(fileHandle);
return status;
}
NTSTATUS WriteResponseAppend(UNICODE_STRING response, HANDLE fileHandle)
{
NTSTATUS status;
IO_STATUS_BLOCK ioStatusBlock;
status = ZwWriteFile(fileHandle, NULL, NULL, NULL, &ioStatusBlock, response.Buffer, response.Length / 2, NULL, NULL);
if (status != STATUS_SUCCESS) {
WriteLog("[LyKernelService] Failed to write to file, status = 0x%x\n", status);
}
return status;
}
NTSTATUS WriteResponseExists(UNICODE_STRING filePath, PBOOLEAN exists)
{
NTSTATUS status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES objectAttributes = { 0 };
IO_STATUS_BLOCK ioStatusBlock = { 0 };
HANDLE fileHandle = NULL;
InitializeObjectAttributes(&objectAttributes, &filePath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwOpenFile(&fileHandle, FILE_READ_ATTRIBUTES, &objectAttributes, &ioStatusBlock, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
if (status != STATUS_SUCCESS) {
*exists = FALSE;
return status;
}
if (fileHandle == NULL) {
*exists = FALSE;
return STATUS_INVALID_HANDLE;
}
*exists = TRUE;
ZwClose(fileHandle);
return STATUS_SUCCESS;
}
NTSTATUS WriteResponseDelete(UNICODE_STRING filePath)
{
NTSTATUS status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES objectAttributes = { 0 };
IO_STATUS_BLOCK ioStatusBlock = { 0 };
HANDLE fileHandle = NULL;
InitializeObjectAttributes(&objectAttributes, &filePath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwOpenFile(&fileHandle, FILE_DELETE_CHILD, &objectAttributes, &ioStatusBlock, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
if (status != STATUS_SUCCESS) {
WriteLog("[LyKernelService] Failed to open file %wZ, status = 0x%x\n", filePath, status);
return status;
}
if (fileHandle == NULL) {
WriteLog("[LyKernelService] Failed to open file %wZ\n", filePath);
return STATUS_INVALID_HANDLE;
}
status = ZwDeleteFile(&objectAttributes);
if (status != STATUS_SUCCESS) {
WriteLog("[LyKernelService] Failed to delete file %wZ, status = 0x%x\n", filePath, status);
return status;
}
ZwClose(fileHandle);
return STATUS_SUCCESS;
}
NTSTATUS RetOpenFileHandle(UNICODE_STRING uDelFileName, PHANDLE pFileHandle)
{
NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
IO_STATUS_BLOCK iostu;
HANDLE hFileHandle = 0;
if (pFileHandle == NULL)
return STATUS_UNSUCCESSFUL;
if (KeGetCurrentIrql() > PASSIVE_LEVEL)
return 0;
if (uDelFileName.Length < 0 || uDelFileName.MaximumLength < 0)
{
return 0;
}
OBJECT_ATTRIBUTES ObjAttribute;
ObjAttribute.ObjectName = &uDelFileName;
ObjAttribute.SecurityDescriptor = NULL;
ObjAttribute.SecurityQualityOfService = NULL;
ObjAttribute.Attributes = OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE;
ObjAttribute.Length = sizeof(OBJECT_ATTRIBUTES);
/* InitializeObjectAttributes(
&ObjAttribute,
&uDelFileName,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
NULL, NULL);*/
ntStatus = IoCreateFile(&hFileHandle,
FILE_READ_ATTRIBUTES,
&ObjAttribute,
&iostu,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_DELETE,
FILE_OPEN,
0,
NULL,
0,
CreateFileTypeNone,
NULL,
IO_NO_PARAMETER_CHECKING);
*pFileHandle = hFileHandle;
return ntStatus;
}
NTSTATUS CallBackIrpCompleteionProc(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
{
//操作系统会设置这个回调
Irp->UserIosb->Status = Irp->IoStatus.Status;
Irp->UserIosb->Information = Irp->IoStatus.Information;
KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE);
IoFreeIrp(Irp);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS PassFileattribute(PFILE_OBJECT pFileObj)
{
/*
1.申请IRP,初始化IRP
2.初始化同步事件,以及设置回调.
3.设置文件属性为默认
4.发送IRP
*/
PDEVICE_OBJECT pNextDeviceObj = NULL;
PIRP pAllocIrp = NULL;
KEVENT IrpSynEvent = { 0 }; //Irp同步需要的事件同步
FILE_BASIC_INFORMATION fileBasciInfo = { 0 };
IO_STATUS_BLOCK iostu;
PIO_STACK_LOCATION IrpStack;
//通过文件对象.获取其设备对象指针
pNextDeviceObj = IoGetRelatedDeviceObject(pFileObj);
if (pNextDeviceObj == NULL)
return STATUS_UNSUCCESSFUL;
//通过设备对象指针.确定申请的IRP的大小,注意在完成设置里面进行释放.
pAllocIrp = IoAllocateIrp(pNextDeviceObj->StackSize, TRUE);
if (pAllocIrp == NULL)
return STATUS_UNSUCCESSFUL;
//初始化Irp
//设置为自动,设置为无信号.
KeInitializeEvent(&IrpSynEvent, SynchronizationEvent, FALSE);
fileBasciInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
pAllocIrp->AssociatedIrp.SystemBuffer = &fileBasciInfo;
pAllocIrp->UserIosb = &iostu;
pAllocIrp->UserEvent = &IrpSynEvent;
pAllocIrp->Tail.Overlay.OriginalFileObject = pFileObj;
pAllocIrp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
//获取下层堆栈.进行设置.
//IrpStack =
IrpStack = IoGetNextIrpStackLocation(pAllocIrp);
IrpStack->MajorFunction = IRP_MJ_SET_INFORMATION;
IrpStack->DeviceObject = pNextDeviceObj;
IrpStack->FileObject = pFileObj;
IrpStack->Parameters.SetFile.Length = sizeof(FILE_BASIC_INFORMATION);
IrpStack->Parameters.SetFile.FileObject = pFileObj;
IrpStack->Parameters.SetFile.FileInformationClass = FileBasicInformation;
//设置完成例程
IoSetCompletionRoutine(pAllocIrp, CallBackIrpCompleteionProc, &IrpSynEvent, TRUE, TRUE, TRUE);
//发送IRP
IoCallDriver(pNextDeviceObj, pAllocIrp);
//等待完成.
KeWaitForSingleObject(&IrpSynEvent, Executive, KernelMode, TRUE, NULL);
return STATUS_SUCCESS;
}
NTSTATUS FsDeleteFile(PFILE_OBJECT pFileObj)
{
/*
1.申请IRP,初始化IRP
2.初始化同步事件,以及设置回调.
3.设置文件属性为默认
4.发送IRP
核心:
核心是设置 FileObject中的域.进而删除正在运行中的文件
*/
PDEVICE_OBJECT pNextDeviceObj = NULL;
PIRP pAllocIrp = NULL;
KEVENT IrpSynEvent = { 0 }; //Irp同步需要的事件同步
FILE_DISPOSITION_INFORMATION fileBasciInfo = { 0 }; //注意此位置.已经变化为 FILE_DISPOSITION_INFORMATION
IO_STATUS_BLOCK iostu;
PIO_STACK_LOCATION IrpStack;
PSECTION_OBJECT_POINTERS pFileExe; //注意此属性要设置为0.欺骗系统进行删除
//通过文件对象.获取其设备对象指针
pNextDeviceObj = IoGetRelatedDeviceObject(pFileObj);
if (pNextDeviceObj == NULL)
return STATUS_UNSUCCESSFUL;
//通过设备对象指针.确定申请的IRP的大小,注意在完成设置里面进行释放.
pAllocIrp = IoAllocateIrp(pNextDeviceObj->StackSize, TRUE);
if (pAllocIrp == NULL)
return STATUS_UNSUCCESSFUL;
//初始化Irp
//设置为自动,设置为无信号.
KeInitializeEvent(&IrpSynEvent, SynchronizationEvent, FALSE);
fileBasciInfo.DeleteFile = TRUE; //设置标记为删除
pAllocIrp->AssociatedIrp.SystemBuffer = &fileBasciInfo;
pAllocIrp->UserIosb = &iostu;
pAllocIrp->UserEvent = &IrpSynEvent;
pAllocIrp->Tail.Overlay.OriginalFileObject = pFileObj;
pAllocIrp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
//获取下层堆栈.进行设置.
//IrpStack =
IrpStack = IoGetNextIrpStackLocation(pAllocIrp);
IrpStack->MajorFunction = IRP_MJ_SET_INFORMATION;
IrpStack->DeviceObject = pNextDeviceObj;
IrpStack->FileObject = pFileObj;
IrpStack->Parameters.SetFile.Length = sizeof(FILE_DISPOSITION_INFORMATION);
IrpStack->Parameters.SetFile.FileObject = pFileObj;
IrpStack->Parameters.SetFile.FileInformationClass = FileDispositionInformation;
//设置完成例程
IoSetCompletionRoutine(pAllocIrp, CallBackIrpCompleteionProc, &IrpSynEvent, TRUE, TRUE, TRUE);
//删除正在运行中的文件.
pFileExe = pFileObj->SectionObjectPointer;
pFileExe->DataSectionObject = 0;
pFileExe->ImageSectionObject = 0;
//发送IRP
IoCallDriver(pNextDeviceObj, pAllocIrp);
//等待完成.
KeWaitForSingleObject(&IrpSynEvent, Executive, KernelMode, TRUE, NULL);
return STATUS_SUCCESS;
}
NTSTATUS IrpDeleteFileRun(UNICODE_STRING uDelFileName)
{
NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
/*
1.首先通过发送IRP去掉文件的属性
2.设置文件属性为删除.进行发送IRP强删文件.
*/
HANDLE hFileHandle = { 0 };
PFILE_OBJECT pFileObject = NULL;
//sep1 : OpenFile Get File Handle
ntStatus = RetOpenFileHandle(uDelFileName, &hFileHandle);
if (!NT_SUCCESS(ntStatus))
{
WriteLog("[LyKernelService] Failed to open file %wZ, status = 0x%x\n", uDelFileName, ntStatus);
goto ExitAnRelease;
}
//sep2: Chang File Handle to FileObject
ntStatus = ObReferenceObjectByHandle(
hFileHandle,
GENERIC_ALL,
*IoFileObjectType,
KernelMode,
(PVOID*)&pFileObject,
NULL);
if (!NT_SUCCESS(ntStatus))
{
WriteLog("[LyKernelService] Failed to get file object, status = 0x%x\n", ntStatus);
goto ExitAnRelease;
}
//setp 3: Pass File Atribute
ntStatus = PassFileattribute(pFileObject);
if (!NT_SUCCESS(ntStatus))
{
WriteLog("[LyKernelService] Failed to pass file attribute, status = 0x%x\n", ntStatus);
goto ExitAnRelease;
}
//setp 4: Send Irp DeleteFile
ntStatus = FsDeleteFile(pFileObject);
if (!NT_SUCCESS(ntStatus))
{
WriteLog("[LyKernelService] Failed to send delete file irp, status = 0x%x\n", ntStatus);
goto ExitAnRelease;
}
ExitAnRelease:
if (pFileObject != NULL)
ObDereferenceObject(pFileObject);
if (hFileHandle != NULL)
ZwClose(hFileHandle);
return ntStatus;
}
注意在使用file.h代码时一定要先使用ZwClose()对已获得的文件句柄释放掉(或者自己写一个强制解锁文件),否则会打印"0xC0000043"错误,即"STATUS_SHARING_VIOLATION"错误.对应代码其实不难,主要是可以根据Microsoft提供的文档进行开发
7万+

被折叠的 条评论
为什么被折叠?



