Windows驱动开发入门-文件管理技术

文件管理内核API

创建文件或目录

InitializeObjectAttributes

打开文件、注册表或设备都需要先用这个初始化一个OBJECT_ATTRIBUTES属性:

1
2
3
4
5
6
7
VOID InitializeObjectAttributes(
OUT POBJECT_ATTRIBUTES InitializedAttributes,
IN PUNICODE_STRING ObjectName,
IN ULONG Attributes,
IN HANDLE RootDirectory,
IN PSECURITY_DESCRIUPTOR SecurityDescriptor
)

IO_STATUS_BLOCK

常用于表示一个操作的结果。

1
2
3
4
5
6
7
typedef struct _IO_STATUS_BLOCK{
union{
NTSTATUS Status;
PVOID Pointer;
};
ULONG_PTR Infromation;
}IO_STATUS_BLOCK,*PIO_STATUS_BLOCK;

一般用不上Pointer,一般用Status,返回STATUS_SUCCESS即为成功。不成功时Status返回错误码,进一步信息保存在Information中,常见的有:文件被成功创建FILE_CREATED,文件被打开FILE_OPENED,文件被覆盖FILE_OVERWRITTEN,文件被替换FILE_SUPERSEDED,文件已存在FILE_EXISTS,文件不存在而失败FILE_DOES_NOT_EXISTS。

ZwCreateFile

NTDLL.DLL中Zw开头跟Nt开头的都同一个东西。

创建一个新文件或打开一个已存在文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
NTSTATUS ZwCreateFile(
_Out_ PHANDLE FileHandle,
//文件句柄
_In_ ACCESS_MASK DesiredAccess,
//对象访问申请的权限
//写内容FILE_WRITE_DATA 读内容FILE_READ_DATA 删除或改名FILE_DELETE
//设置写文件属性FILE_WRITE_ATTRIBUTES 设置读文件属性FILE_READ_ATTRIBUTES
//常用读权限GENERIC_READ 常用写权限GENERIC_WRITE 常用全部权限GENERIC_ALL
//同步打开文件SYNCHRONIZE
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
//对象名称
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
//最终完成状态
_In_opt_ PLARGE_INTEGER AllocationSize,
_In_ ULONG FileAttributes,
_In_ ULONG ShareAccess,
//0或以下共享访问 0独占访问
//FILE_SHARE_READ FILE_SHARE_WRITE FILE_SHARE_DELETE
_In_ ULONG CreateDisposition,
//FILE_CREATE存在返回错误否则创建 FILE_OPEN存在打开否则错误 FILE_OPEN_IF存在打开否则创建 FILE_DIRECTORY_FILE创建的是目录时
//FILE_OVERWRITE覆盖 FILE_OVERWRITE_IF新建或覆盖 FILE_SUPERSEDE新建或取代
_In_ ULONG CreateOptions,
//同步打开FILE_SYNCHRONOUS_IO_NONALERT 建议同步 要不经常返回STATUS_PENDING未决 DesiredAccess必须有SYNCHRONIZE
//文件FILE_NON_DIRECTORY_FILE 目录FILE_DIRECTORY_FILE
//不缓冲直接往磁盘上操作FILE_NO_INTERMEDIATE_BUFFERING 每次文件读写都需以磁盘扇区大小字节数对齐
_In_opt_ PVOID EaBuffer,
_In_ ULONG EaLength
)//成功STATUS_SUCCESS 否则NTSTATUS错误代码

例子

在内核中所有文件路径前必须加上“/??/”,例如“/??/C:\test.txt”。必须用ZwClose关闭句柄。

1
2
3
4
5
6
7
8
9
10
11
12
BOOLEAN MyCreateFile(UNICODE_STRING ustrFilePath) {
HANDLE hFile = NULL;
OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
IO_STATUS_BLOCK iosb = { 0 };
NTSTATUS status = STATUS_SUCCESS;
InitializeObjectAttrbutes(&ObjectAttributes, &ustrFilePath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwCreateFile(&hFile, GENERIC_READ, &ObjectAttributes, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (!NT_SUCCESS(status))
return FALSE;
ZwClose(hFile);
return TRUE;
};

删除文件或空目录

ZwDeleteFile

删除指定文件。

1
2
3
NTSTATUS ZwDeleteFile(
_In_ POBJECT_ATTRIBUTES ObjectAttributes
)//同上

例子

对应应用层的DeleteFileRemoveDirectory

1
2
3
4
5
6
7
8
9
BOOLEAN MyDeleteFileOrFileFolder(UNICODE_STRING ustrFilePath) {
OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
NTSTATUS status = STATUS_SUCCESS;
InitializeObjectAttrbutes(&ObjectAttributes, &ustrFilePath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwDeleteFile(&ObjectAttributes);
if (!NT_SUCCESS(status))
return FALSE;
return TRUE;
};

获取文件大小

ZwQueryInformationFile

返回文件对象各种信息。

1
2
3
4
5
6
7
8
9
10
NTSTATUS ZwQueryInformationFile(
_In_ HANDLE FileHandle,
//处理文件对象
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
//写入FileInformation缓冲区实际字节数
_Out_ PVOID FileInformation,
//写入文件对象请求信息
_In_ ULONG Length,
_In_ FILE_INFORMATION_CLASS FileInformationClass
)//同上

FILE_STANDARD_INFORMATION

1
2
3
4
5
6
7
8
9
10
11
12
typedef struct _FILE_STANDARD_INFORMATION{
LARGE_INTEGER AllocationSize;
//文件分配大小 扇区或簇大小倍数
LARGE_INTEGER EndOfFile;
//文件大小
ULONG NumberOfLinks;
//硬链接数
BOOLEAN DeletePending;
//TRUE表示已删除挂起
BOOLEAN Directory;
//TRUE为目录
}FILE_STANDARD_INFORMATION,*PFILE_STANDARD_INFORMATION;

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ULONG64 MyGetFileSize(UNICODE_STRING ustrFileName) {
HANDLE hFile = NULL;
OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
IO_STATUS_BLOCK iosb = { 0 };
NTSTATUS status = STATUS_SUCCESS;
FILE_STANDARD_INFORMATION fsi = { 0 };
InitializeObjectAttributes(&ObjectAttributes, &ustrFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwCreateFile(&hFile, GENERIC_READ, &ObjectAttributes, &iosb, NULL, 0, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (!NT_SUCCESS(status))
return 0;
status = ZwQueryInformationFile(hFile, &iosb, &fsi, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation);
if (!NT_SUCCESS(status))
return 0;
return fsi.EndOfFile.QuadPart;
};

读写文件

ExAllocatePool

指定分配类型的池内存,返回指向分配块的指针。非分页池内存很稀缺,用完一定要ExFreePool

1
2
3
4
5
6
PVOID ExAllocatePool(
_In_ POOL_TYPE PoolType,
//NonPagedPool非分页内存池,可在任何IRQL上访问 但很稀缺
_In_ SIZE_T NumberOfBytes
//要分配的字节数
)//成功返回指针 否则NULL

ZwReadFile

从打开的文件中读取数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
NTSTATUS ZwReadFile(
_In_ HANDLE FileHandle,
_In_opt_ HANDLE Event,
_In_opt_ PIO_APC_ROUTINE ApcRoutine,
_In_opt_ PVOID ApcContext,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
//从中读取字节数
_Out_ PVOID Buffer,
//接收读取的数据
_In_ ULONG Length,
//缓冲区大小
_In_opt_ PLARGE_INTEGER ByteOffset,
//文件中起始字节偏移量
_In_opt_ PULONG Key
)

ZwWriteFile

向打开的文件写入数据,结构与ZwReadFile完全一样。

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
BOOLEAN MyReadFile(UNICODE_STRING ustrFileName, LARGE_INTEGER liOffset, PUCHAR pReadData, PULONG pulReadDataSize) {
OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
NTSTATUS status = STATUS_SUCCESS;
HANDLE hFile = NULL;
IO_STATUS_BLOCK iosb = { 0 };
InitializeObjectAttributes(&ObjectAttributes, &ustrFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwCreateFile(&hFile, GENERIC_READ, &ObjectAttributes, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (!NT_SUCCESS(status))
return FALSE;
RtlZeroMemory(&iosb, sizeof(iosb));
status = ZwReadFile(hFile, NULL, NULL, NULL, &iosb, pReadData, *pulReadDataSize, &liOffset, NULL);
if (!NT_SUCCESS(status)) {
*pulReadDataSize = iosb.Information;
ZwClose(hFile);
return FALSE;
};
*pulReadDataSize = iosb.Information;
ZwClose(hFile);
return TRUE;
};
BOOLEAN MyWriteFile(UNICODE_STRING ustrFileName, LARGE_INTEGER liOffset, PUCHAR pWriteData, PULONG pulWriteDataSize) {
OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
IO_STATUS_BLOCK iosb = { 0 };
NTSTATUS status = STATUS_SUCCESS;
HANDLE hFile = NULL;
InitializeObjectAttributes(&ObjectAttributes, GENERIC_WRITE, &ObjectAttributes, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_IF, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
status = ZwCreateFile(&hFile, GENERIC_WRITE, &ObjectAttributes, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_IF, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (!NT_SUCCESS(status))
return FALSE;
RtlZeroMemory(&iosb, sizeof(iosb));
status = ZwWriteFile(hFile, NULL, NULL, NULL, &iosb, pWriteData, *pulWriteDataSize, &liOffset, NULL);
if (!NT_SUCCESS(status)) {
*pulWriteDataSize = iosb.Information;
ZwClose(hFile);
return FALSE;
};
*pulWriteDataSize = iosb.Information;
ZwClose(hFile);
return TRUE;
};

重命名文件

UNICODE_STRING

用于储存一个不以\x00为结束符,明确规定长度的字符串。

1
2
3
4
5
6
7
8
typedef struct _UNICODE_STRING{
USHORT Length;
//有效字符串长度
USHORT MaximumLength;
//字符串最大长度
PWSTR Buffer;
//指向字符串指针
}UNICODE_STRING,*PUNICODE_STRING;

ZwSetInformationFile

更改有关文件对象各种信息,用法与ZwQueryInformationFile类似。

FILE_RENAME_INFORMATION

1
2
3
4
5
6
7
8
9
10
typedef struct _FILE_RENAME_INFORMATION(
BOOLEAN ReplaceIfExists;
//存在时TRUE替换 FALSE失败
HANDLE RootDirectory;
//不移动目录或FileName包含完整路径名时为NULL 否则为根目录句柄
ULONG FileNameLength;
//新名长度 单位字节
WCHAR FileName[1];
//新名宽字符串第一个字符
)FILE_RENAME_INFORMATION,*PFILE_RENAME_INFORMATION

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
BOOLEAN MyRenameFileOrFileFolder(UNICODE_STRING ustrSrcFileName, UNICODE_STRING ustrDestFileName) {
PFILE_RENAME_INFORMATION pRenameInfo = NULL;
ULONG ulLength = (2 * 4096 + sizeof(PFILE_RENAME_INFORMATION)) * 0x2000;
OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
NTSTATUS status = STATUS_SUCCESS;
HANDLE hFile = NULL;
IO_STATUS_BLOCK iosb = { 0 };
pRenameInfo = (PFILE_RENAME_INFORMATION)ExAllocatePool(NonPagedPool, ulLength);
if (NULL == pRenameInfo)
return FALSE;
RtlZeroMemory(pRenameInfo, ulLength);
//设置重命名信息
pRenameInfo->FileNameLength = ustrDestFileName.Length;
wcscpy(pRenameInfo->FileName, ustrDestFileName.Buffer); //不建议这么用 wcscpy是以\x00为结尾的
pRenameInfo->ReplaceIfExists = 0;
pRenameInfo->RootDirectory = NULL;
InitializeObjectAttributes(&ObjectAttributes, &ustrSrcFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwCreateFIle(&hFile, SYNCHRONIZE | DELETE, &ObjectAttributes, &iosb, NULL, 0, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT | FILE_NO_INTERMEDIATE_BUFFERING, NULL, 0);
if (!NT_SUCCESS(status)) {
ExFreePool(pRenameInfo);
return FALSE;
};
status = ZwSetInformationFile(hFile, &iosb, pRenameInfo, ulLength, FileRenameInformation);
if (!NT_SUCCESS(status)) {
ZwClose(hFile);
ExFreePool(pRenameInfo);
return FALSE;
};
ExFreePool(pRenameInfo);
ZwClose(hFile);
return TRUE;
};

文件遍历

ZwQueryDirectoryFile

在文件句柄指定目录中返回文件各种信息,太复杂了不写了。

1
2
3
4
5
6
7
8
9
10
11
12
13
NTSTATUS ZwQueryDirectoryFile(
_In_ HANDLE FileHandle,
_In_opt_ HANDLE Event,
_In_opt_ PIO_APC_ROUTINE ApcRoutine,
_In_opt_ PVOID ApcContext,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_Out_ PVOID FileInformation,
_In_ ULONG Length,
_In_ FILE_INFORMATION_CLASS FileInformationClass,
_In_ BOOLEAN ReturnSingleEntry,
_In_opt_ PUNICODE_STRING FileName,
_In_ BOOLEAN RestartScan
)

FILE_BOTH_DIR_INFORMATION

略。

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
BOOLEAN MyQueryFileAndFileFolder(UNICODE_STRING ustrPath) {
HANDLE hFile = NULL;
OBJECT_ATTRIBUTES objectAttributes = { 0 };
IO_STATUS_BLOCK iosb = { 0 };
NTSTATUS status = STATUS_SUCCESS;
InitializeObjectAttributes(&objectAttributes, &ustrPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwCreateFile(&hFile, FILE_LIST_DIRECTORY | SYNCHRONIZE | FILE_ANY_ACCESS,
&objectAttributes, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
NULL, 0);
if (!NT_SUCCESS(status))
return FALSE;
ULONG ulLength = (2 * 4096 + sizeof(FILE_BOTH_DIR_INFORMATION)) * 0x2000;
PFILE_BOTH_DIR_INFORMATION pDir = ExAllocatePool(PagedPool, ulLength);
PFILE_BOTH_DIR_INFORMATION pBeginAddr = pDir; //保存原始pDir 否则后面pDir偏移后无法ExFreePool
status = ZwQueryDirectoryFile(hFile, NULL, NULL, NULL, &iosb, pDir, ulLength, FileBothDirectoryInformation, FALSE, NULL, FALSE);
if (!NT_SUCCESS(status)) {
ExFreePool(pDir);
ZwClose(hFile);
return FALSE;
};
UNICODE_STRING ustrTemp;
UNICODE_STRING ustrOne;
UNICODE_STRING ustrTwo;
RtlInitUnicodeString(&ustrOne, L".");
RtlInitUnicodeString(&ustrTwo, L"..");
WCHAR wcFileName[1024] = { 0 };
while (TRUE) {
RtlZeroMemory(wcFileName, 1024);
RtlCopyMemory(wcFileName, pDir->FileName, pDir->FileNameLength);
RtlInitUnicodeString(&ustrTemp, wcFileName);
if ((0 != RtlCompareUnicodeString(&ustrTemp, &ustrOne, TRUE)) && (0 != RtlCompareUnicodeString(&ustrTemp, &ustrTwo, TRUE))) { //跳过.和..
if (pDir->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
DbgPrint("[目录] 创建时间: %u | 改变时间: %u 目录名: %wZ \n", pDir->CreationTime, &pDir->ChangeTime, &ustrTemp);
else
DbgPrint("[文件] 创建时间: %u | 改变时间: %u | 文件名: %wZ \n", pDir->CreationTime, &pDir->ChangeTime, &ustrTemp);
};
if (0 == pDir->NextEntryOffset)
break;
pDir = (PFILE_BOTH_DIR_INFORMATION)((PUCHAR)pDir + pDir->NextEntryOffset);
};
ExFreePool(pBeginAddr);
ZwClose(hFile);
return TRUE;
};
VOID UnDriver(PDRIVER_OBJECT pDriver) {
DbgPrint("驱动卸载成功 \n");
};
NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT pDriver, _In_ PUNICODE_STRING RegistryPath) {
UNICODE_STRING ustrQueryFile;
RtlInitUnicodeString(&ustrQueryFile, L"\\??\\C:\\Windows");
MyQueryFileAndFileFolder(ustrQueryFile);
DbgPrint("驱动加载成功 \n");
pDriver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
};

关于文件系统重定向

32位程序在64位系统上运行时,对%windir%\System32目录的操作都会被重定向到%windir%\SysWOW64目录,可以暂时关闭这一功能。System32下有些子目录不重定向:catroot、catroot2、drivers\etc、logfiles、spool。

Wow64DisableWow64FsRedirection

关闭文件系统重定向功能。

1
2
3
BOOL WINAPI Wow64DisableWow64FsRedirection(
_Out_ PVOID* OldValue
)

Wow64RevertWow64FsRedirection

恢复文件系统重定向功能。

1
2
3
BOOL WINAPI Wow64RevertWow64FsRedirection(
_in_ PVOID OldValue
)

例子

1
2
3
4
5
6
7
8
9
10
PVOID pOldValue = NULL;
BOOL bRet = ::Wow64DisableWow64FsRedirection(&pOldValue);
if (bRet == TRUE) {
HANDLE hFile = ::CreateFile(TEXT("C:\\Windows\\system32\\testfile.txt"), GENERIC_READ, 0, NULL, CREATE_ALWAYS, 0, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
::CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
};
::Wow64RevertWow64FsRedirection(pOldValue);
};

IRP

基础知识

文件操作涉及WIN32 API、Native API、File System、Filter Driver等层次,其中FSD(File System Driver)时文件API函数经过Native API到达驱动层,驱动程序可模仿操作系统的操作,向FSD直接发送IRP(I/O Request Packet)来管理文件,但需要驱动程序自己构建IRP就比较麻烦。

IoAllocateIrp

申请创建一个IRP。

1
2
3
4
5
NTKERNELAPI PIRP IoAllocateIrp(
_In_ CCHAR StackSize,
//要分配给IRP的I/O堆栈数量
_In_ BOOLEAN ChargeQuota
)

IoCallDriver

发送一个IRP。

1
2
3
4
5
6
NTSTATUS IoCallDriver(
_In_ PDEVICE_OBJECT DeviceObject,
//设备对象
_In_out_ PIRP Irp
//IRP指针
)

例子&实战

主程序Driver.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef _DRIVER_H_
#define _DRIVER_H_
#include <ntddk.h>
#define DEV_NAME L"\\Device\\IRP_FILE_DEV_NAME"
#define SYM_NAME L"\\DosDevices\\IRP_FILE_SYM_NAME"
#define IOCTL_TEST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
VOID DriverUnload(PDRIVER_OBJECT pDriverObject);
NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp);
NTSTATUS DriverControlHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp);
NTSTATUS CreateDevice(PDRIVER_OBJECT pDriverObject);
// IRP 操作文件测试
VOID MyIrpFileTest();
#endif

主程序Driver.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include "IrpFile.h"
#include "FileManage.h"
#include "Driver.h"
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath){
DbgPrint("Enter DriverEntry\n");
NTSTATUS status = STATUS_SUCCESS;
pDriverObject->DriverUnload = DriverUnload;
pDriverObject->MajorFunction[IRP_MJ_CREATE] = DriverDefaultHandle;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverDefaultHandle;
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverControlHandle;
status = CreateDevice(pDriverObject);
// IRP 操作文件测试
MyIrpFileTest();
DbgPrint("Leave DriverEntry\n");
return status;
};
VOID DriverUnload(PDRIVER_OBJECT pDriverObject){
DbgPrint("Enter DriverUnload\n");
if (pDriverObject->DeviceObject)
IoDeleteDevice(pDriverObject->DeviceObject);
UNICODE_STRING ustrSymName;
RtlInitUnicodeString(&ustrSymName, SYM_NAME);
IoDeleteSymbolicLink(&ustrSymName);
DbgPrint("Leave DriverUnload\n");
};
NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp){
DbgPrint("Enter DriverDefaultHandle\n");
NTSTATUS status = STATUS_SUCCESS;
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
DbgPrint("Leave DriverDefaultHandle\n");
return status;
};
NTSTATUS DriverControlHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp){
DbgPrint("Enter DriverControlHandle\n");
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION pIoStackLocation = IoGetCurrentIrpStackLocation(pIrp);
ULONG ulInputLen = pIoStackLocation->Parameters.DeviceIoControl.InputBufferLength;
ULONG ulOutputLen = pIoStackLocation->Parameters.DeviceIoControl.OutputBufferLength;
ULONG ulControlCode = pIoStackLocation->Parameters.DeviceIoControl.IoControlCode;
PVOID pBuffer = pIrp->AssociatedIrp.SystemBuffer;
ULONG ulInfo = 0;
switch (ulControlCode){
case IOCTL_TEST:
break;
default:
break;
};
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = ulInfo;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
DbgPrint("Leave DriverControlHandle\n");
return status;
};
NTSTATUS CreateDevice(PDRIVER_OBJECT pDriverObject){
DbgPrint("Enter CreateDevice\n");
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_OBJECT pDevObj = NULL;
UNICODE_STRING ustrDevName, ustrSymName;
RtlInitUnicodeString(&ustrDevName, DEV_NAME);
RtlInitUnicodeString(&ustrSymName, SYM_NAME);
status = IoCreateDevice(pDriverObject, 0, &ustrDevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDevObj);
if (!NT_SUCCESS(status)){
DbgPrint("IoCreateDevice Error[0x%X]\n", status);
return status;
};
status = IoCreateSymbolicLink(&ustrSymName, &ustrDevName);
if (!NT_SUCCESS(status)){
DbgPrint("IoCreateSymbolicLink Error[0x%X]\n", status);
return status;
};
DbgPrint("Leave CreateDevice\n");
return status;
};
// IRP 操作文件测试
// 注意:路径不需要加 \??\ 作为前缀
VOID MyIrpFileTest(){
// 创建文件
UNICODE_STRING ustrCreateFile;
RtlInitUnicodeString(&ustrCreateFile, L"C:\\520.txt");
MyCreateFile(ustrCreateFile);
DbgPrint("Create File OK.\n");
// 获取文件大小
UNICODE_STRING ustrFileSize;
RtlInitUnicodeString(&ustrFileSize, L"C:\\520.exe");
ULONG64 ullFileSize = MyGetFileSize(ustrFileSize);
DbgPrint("FileSize = %I64d Bytes\n", ullFileSize);
// 设置文件隐藏属性
UNICODE_STRING ustrHideFile;
RtlInitUnicodeString(&ustrHideFile, L"C:\\520.exe");
MyHideFile(ustrHideFile);
DbgPrint("Hide File OK.\n");
// 遍历文件夹和文件
UNICODE_STRING ustrQueryFile;
RtlInitUnicodeString(&ustrQueryFile, L"C:\\");
MyQueryFileAndFileFolder(ustrQueryFile);
DbgPrint("Query File OK.\n");
// 文件数据写入
UNICODE_STRING ustrWriteFile;
LARGE_INTEGER liWriteOffset = { 0 };
UCHAR szWriteData[256] = "Who Are You? I am Demon`Gan.";
ULONG ulWriteDataLength = 1 + strlen(szWriteData);
RtlInitUnicodeString(&ustrWriteFile, L"C:\\520.txt");
MyWriteFile(ustrWriteFile, liWriteOffset, szWriteData, &ulWriteDataLength);
DbgPrint("MyWriteFile OK.\n");
// 文件数据读取
UNICODE_STRING ustrReadFile;
LARGE_INTEGER liReadOffset = { 0 };
UCHAR szReadData[256] = { 0 };
ULONG ulReadDataLength = 256;
RtlInitUnicodeString(&ustrReadFile, L"C:\\520.txt");
MyReadFile(ustrReadFile, liReadOffset, szReadData, &ulReadDataLength);
DbgPrint("MyReadFile:[%s]\n", szReadData);
};

FileMange.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef _FILE_MANAGE_H_
#define _FILE_MANAGE_H
#include <ntifs.h>
#include <ntstatus.h>
// 注意: 路径不需要加 \??\ 作为前缀
// 创建或打开文件
BOOLEAN MyCreateFile(UNICODE_STRING ustrFilePath);
// 获取文件大小
ULONG64 MyGetFileSize(UNICODE_STRING ustrFileName);
// 设置文件隐藏属性
BOOLEAN MyHideFile(UNICODE_STRING ustrFileName);
// 遍历文件夹和文件
BOOLEAN MyQueryFileAndFileFolder(UNICODE_STRING ustrPath);
// 读取文件数据
BOOLEAN MyReadFile(UNICODE_STRING ustrFileName, LARGE_INTEGER liOffset, PUCHAR pReadData, PULONG pulReadDataSize);
// 向文件写入数据
BOOLEAN MyWriteFile(UNICODE_STRING ustrFileName, LARGE_INTEGER liOffset, PUCHAR pWriteData, PULONG pulWriteDataSize);
#endif

FileManage.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#include "FileManage.h"
#include "IrpFile.h"
#include <ntstatus.h>
VOID ShowError(CHAR *lpszText, NTSTATUS status){
DbgPrint("%s Error! Error Code: 0x%08X\n", lpszText, status);
};
// 创建或者打开文件
BOOLEAN MyCreateFile(UNICODE_STRING ustrFilePath){
PFILE_OBJECT hFile = NULL;
IO_STATUS_BLOCK iosb = { 0 };
NTSTATUS status = STATUS_SUCCESS;
// 创建或者打开文件
status = IrpCreateFile(&hFile, GENERIC_READ, &ustrFilePath, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (!NT_SUCCESS(status)){
ShowError("IrpCreateFile", status);
return FALSE;
};
// 关闭句柄
ObDereferenceObject(hFile);
return TRUE;
};
// 获取文件大小
ULONG64 MyGetFileSize(UNICODE_STRING ustrFileName){
PFILE_OBJECT hFile = NULL;
OBJECT_ATTRIBUTES objectAttributes = { 0 };
IO_STATUS_BLOCK iosb = { 0 };
NTSTATUS status = STATUS_SUCCESS;
FILE_STANDARD_INFORMATION fsi = { 0 };
// 获取文件句柄
status = IrpCreateFile(&hFile, GENERIC_READ, &ustrFileName, &iosb, NULL, 0, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (!NT_SUCCESS(status)){
ShowError("IrpCreateFile", status);
return 0;
};
// 获取文件大小信息
status = IrpQueryInformationFile(hFile, &iosb, &fsi, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation);
if (!NT_SUCCESS(status)){
ObDereferenceObject(hFile);
ShowError("IrpQueryInformationFile", status);
return 0;
};
// 关闭句柄
ObDereferenceObject(hFile);
return fsi.EndOfFile.QuadPart;
};
// 设置文件隐藏属性
BOOLEAN MyHideFile(UNICODE_STRING ustrFileName){
PFILE_OBJECT hFile = NULL;
IO_STATUS_BLOCK iosb = { 0 };
NTSTATUS status = STATUS_SUCCESS;
FILE_BASIC_INFORMATION fileBaseInfo = { 0 };
// 设置源文件信息并获取句柄
status = IrpCreateFile(&hFile, GENERIC_READ | GENERIC_WRITE, &ustrFileName, &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)){
ShowError("IrpCreateFile", status);
return FALSE;
};
// 利用IrpSetInformationFile来设置文件信息
RtlZeroMemory(&fileBaseInfo, sizeof(fileBaseInfo));
fileBaseInfo.FileAttributes = FILE_ATTRIBUTE_HIDDEN;
status = IrpSetInformationFile(hFile, &iosb, &fileBaseInfo, sizeof(fileBaseInfo), FileBasicInformation);
if (!NT_SUCCESS(status)){
ObDereferenceObject(hFile);
ShowError("IrpSetInformationFile", status);
return FALSE;
};
// 关闭句柄
ObDereferenceObject(hFile);
return TRUE;
};
// 遍历文件夹和文件
BOOLEAN MyQueryFileAndFileFolder(UNICODE_STRING ustrPath){
PFILE_OBJECT hFile = NULL;
IO_STATUS_BLOCK iosb = { 0 };
NTSTATUS status = STATUS_SUCCESS;
// 获取文件句柄
status = IrpCreateFile(&hFile, FILE_LIST_DIRECTORY | SYNCHRONIZE | FILE_ANY_ACCESS, &ustrPath, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT, NULL, 0);
if (!NT_SUCCESS(status)){
ShowError("IrpCreateFile", status);
return FALSE;
};
// 遍历文件
// 注意此处的大小!!!一定要申请足够内存,否则后面ExFreePool会蓝屏
ULONG ulLength = (2 * 4096 + sizeof(FILE_BOTH_DIR_INFORMATION)) * 0x2000;
PFILE_BOTH_DIR_INFORMATION pDir = ExAllocatePool(PagedPool, ulLength);
// 保存pDir的首地址,用来释放内存使用!!!
PFILE_BOTH_DIR_INFORMATION pBeginAddr = pDir;
// 获取信息
status = IrpQueryDirectoryFile(hFile, &iosb, pDir, ulLength, FileBothDirectoryInformation, NULL);
if (!NT_SUCCESS(status)){
ExFreePool(pDir);
ObDereferenceObject(hFile);
ShowError("IrpQueryDirectoryFile", status);
return FALSE;
};
// 遍历
UNICODE_STRING ustrTemp;
UNICODE_STRING ustrOne;
UNICODE_STRING ustrTwo;
RtlInitUnicodeString(&ustrOne, L".");
RtlInitUnicodeString(&ustrTwo, L"..");
WCHAR wcFileName[1024] = { 0 };
while (TRUE){
// 判断是否是上级目录或是本目录
RtlZeroMemory(wcFileName, 1024);
RtlCopyMemory(wcFileName, pDir->FileName, pDir->FileNameLength);
RtlInitUnicodeString(&ustrTemp, wcFileName);
if ((0 != RtlCompareUnicodeString(&ustrTemp, &ustrOne, TRUE)) && (0 != RtlCompareUnicodeString(&ustrTemp, &ustrTwo, TRUE))){
if (pDir->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
// 目录
DbgPrint("[DIRECTORY]\t%wZ\n", &ustrTemp);
else
// 文件
DbgPrint("[FILE]\t\t%wZ\n", &ustrTemp);
};
// 遍历完毕
if (0 == pDir->NextEntryOffset){
DbgPrint("\n[QUERY OVER]\n\n");
break;
};
// pDir指向的地址改变了,所以下面ExFreePool(pDir)会出错!!!所以,必须保存首地址
pDir = (PFILE_BOTH_DIR_INFORMATION)((PUCHAR)pDir + pDir->NextEntryOffset);
};
// 释放内存, 关闭文件句柄
ExFreePool(pBeginAddr);
ObDereferenceObject(hFile);
return TRUE;
};
// 读取文件数据
BOOLEAN MyReadFile(UNICODE_STRING ustrFileName, LARGE_INTEGER liOffset, PUCHAR pReadData, PULONG pulReadDataSize){
PFILE_OBJECT hFile = NULL;
IO_STATUS_BLOCK iosb = { 0 };
NTSTATUS status = STATUS_SUCCESS;
// 打开文件
status = IrpCreateFile(&hFile, GENERIC_READ, &ustrFileName, &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)){
ShowError("IrpCreateFile", status);
return FALSE;
};
// 读取文件数据
RtlZeroMemory(&iosb, sizeof(iosb));
status = IrpReadFile(hFile, &iosb, pReadData, *pulReadDataSize, &liOffset);
if (!NT_SUCCESS(status)){
*pulReadDataSize = iosb.Information;
ObDereferenceObject(hFile);
ShowError("IrpReadFile", status);
return FALSE;
};
// 获取实际读取的数据
*pulReadDataSize = iosb.Information;
// 关闭句柄
ObDereferenceObject(hFile);
return TRUE;
};
// 向文件写入数据
BOOLEAN MyWriteFile(UNICODE_STRING ustrFileName, LARGE_INTEGER liOffset, PUCHAR pWriteData, PULONG pulWriteDataSize){
PFILE_OBJECT hFile = NULL;
IO_STATUS_BLOCK iosb = { 0 };
NTSTATUS status = STATUS_SUCCESS;
// 打开文件
status = IrpCreateFile(&hFile, GENERIC_WRITE, &ustrFileName, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_IF, FILE_NO_INTERMEDIATE_BUFFERING | FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (!NT_SUCCESS(status)){
ShowError("IrpCreateFile", status);
return FALSE;
};
// 写入文件数据
RtlZeroMemory(&iosb, sizeof(iosb));
status = IrpWriteFile(hFile, &iosb, pWriteData, *pulWriteDataSize, &liOffset);
if (!NT_SUCCESS(status)){
*pulWriteDataSize = iosb.Information;
ObDereferenceObject(hFile);
ShowError("IrpWriteFile", status);
return FALSE;
};
// 获取实际写入的数据
*pulWriteDataSize = iosb.Information;
// 关闭句柄
ObDereferenceObject(hFile);
return TRUE;
};

IrpFile.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#ifndef _IRP_FILE_H_
#define _IRP_FILE_H_
#include <ntifs.h>
typedef struct _AUX_ACCESS_DATA {
PPRIVILEGE_SET PrivilegesUsed;
GENERIC_MAPPING GenericMapping;
ACCESS_MASK AccessesToAudit;
ACCESS_MASK MaximumAuditMask;
ULONG Unknown[256];
} AUX_ACCESS_DATA, *PAUX_ACCESS_DATA;
NTSTATUS SeCreateAccessState(
PACCESS_STATE AccessState,
PVOID AuxData,
ACCESS_MASK DesiredAccess,
PGENERIC_MAPPING GenericMapping
);
NTSTATUS ObCreateObject(
__in KPROCESSOR_MODE ProbeMode, // 决定是否要验证参数
__in POBJECT_TYPE ObjectType, // 对象类型指针
__in POBJECT_ATTRIBUTES ObjectAttributes, // 对象的属性, 最终会转化成ObAllocateObject需要的OBJECT_CREATE_INFORMATION结构
__in KPROCESSOR_MODE OwnershipMode, // 内核对象?用户对象? 同上
__inout_opt PVOID ParseContext, // 这参数没用
__in ULONG ObjectBodySize, // 对象体大小
__in ULONG PagedPoolCharge, // ...
__in ULONG NonPagedPoolCharge, // ...
__out PVOID *Object // 接收对象体的指针
);
// 完成实例, 设置事件信号量, 并释放IRP
NTSTATUS MyCompleteRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP pIrp,
IN PVOID Context
);
// 创建或者打开文件
// ZwCreateFile
NTSTATUS IrpCreateFile(
OUT PFILE_OBJECT *ppFileObject,
IN ACCESS_MASK DesiredAccess,
IN PUNICODE_STRING pustrFilePath,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER AllocationSize OPTIONAL,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN PVOID EaBuffer OPTIONAL,
IN ULONG EaLength
);
// 文件遍历
// ZwQueryDirectoryFile
NTSTATUS IrpQueryDirectoryFile(
IN PFILE_OBJECT pFileObject,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass,
IN PUNICODE_STRING FileName OPTIONAL
);
// 获取文件的信息
// ZwQueryInformationFile
NTSTATUS IrpQueryInformationFile(
IN PFILE_OBJECT pFileObject,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass
);
// 设置文件信息
// ZwSetInformationFile
NTSTATUS IrpSetInformationFile(
IN PFILE_OBJECT pFileObject,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass
);
// 读文件
// ZwReadFile
NTSTATUS IrpReadFile(
IN PFILE_OBJECT pFileObject,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID Buffer,
IN ULONG Length,
IN PLARGE_INTEGER ByteOffset OPTIONAL
);
// 写文件
// ZwWriteFile
NTSTATUS IrpWriteFile(
IN PFILE_OBJECT pFileObject,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PVOID Buffer,
IN ULONG Length,
IN PLARGE_INTEGER ByteOffset OPTIONAL
);
#endif

IrpFile.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
#include "IrpFile.h"
// 完成实例, 设置事件信号量, 并释放IRP
NTSTATUS MyCompleteRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp, IN PVOID Context){
*pIrp->UserIosb = pIrp->IoStatus;
// 设置事件信号
if (pIrp->UserEvent)
KeSetEvent(pIrp->UserEvent, IO_NO_INCREMENT, FALSE);
// 释放MDL
if (pIrp->MdlAddress){
IoFreeMdl(pIrp->MdlAddress);
pIrp->MdlAddress = NULL;
};
// 释放IRP
IoFreeIrp(pIrp);
pIrp = NULL;
return STATUS_MORE_PROCESSING_REQUIRED;
};
// 创建或者打开文件
// ZwCreateFile
NTSTATUS IrpCreateFile(OUT PFILE_OBJECT *ppFileObject, IN ACCESS_MASK DesiredAccess, IN PUNICODE_STRING pustrFilePath, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PLARGE_INTEGER AllocationSize OPTIONAL, IN ULONG FileAttributes, IN ULONG ShareAccess, IN ULONG CreateDisposition, IN ULONG CreateOptions, IN PVOID EaBuffer OPTIONAL, IN ULONG EaLength){
NTSTATUS status = STATUS_SUCCESS;
ULONG ulFileNameMaxSize = 512;
WCHAR wszName[100] = { 0 };
UNICODE_STRING ustrRootPath;
OBJECT_ATTRIBUTES objectAttributes = { 0 };
HANDLE hRootFile = NULL;
PFILE_OBJECT pRootFileObject = NULL, pFileObject = NULL;
PDEVICE_OBJECT RootDeviceObject = NULL, RootRealDevice = NULL;
PIRP pIrp = NULL;
KEVENT kEvent = { 0 };
ACCESS_STATE accessData = { 0 };
AUX_ACCESS_DATA auxAccessData = { 0 };
IO_SECURITY_CONTEXT ioSecurityContext = { 0 };
PIO_STACK_LOCATION pIoStackLocation = NULL;
// 打开磁盘根目录并获取句柄
wcscpy(wszName, L"\\??\\A:\\");
wszName[4] = pustrFilePath->Buffer[0];
RtlInitUnicodeString(&ustrRootPath, wszName);
DbgPrint("RootPath:%wZ\n", &ustrRootPath);
InitializeObjectAttributes(&objectAttributes, &ustrRootPath, OBJ_KERNEL_HANDLE, NULL, NULL);
status = IoCreateFile(&hRootFile, GENERIC_READ | SYNCHRONIZE, &objectAttributes, IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0, CreateFileTypeNone, NULL, IO_NO_PARAMETER_CHECKING);
if (!NT_SUCCESS(status)){
DbgPrint("IoCreateFile Error[0x%X]", status);
return status;
};
// 获取磁盘根目录文件对象
status = ObReferenceObjectByHandle(hRootFile, FILE_READ_ACCESS, *IoFileObjectType, KernelMode, &pRootFileObject, NULL);
if (!NT_SUCCESS(status)){
ZwClose(hRootFile);
DbgPrint("ObReferenceObjectByHandle Error[0x%X]\n", status);
return status;
};
// 获取磁盘根目录设备对象
RootDeviceObject = pRootFileObject->Vpb->DeviceObject;
RootRealDevice = pRootFileObject->Vpb->RealDevice;
// 关闭磁盘根目录句柄和对象
ObDereferenceObject(pRootFileObject);
ZwClose(hRootFile);
// 创建IRP
pIrp = IoAllocateIrp(RootDeviceObject->StackSize, FALSE);
if (NULL == pIrp){
ObDereferenceObject(pFileObject);
DbgPrint("IoAllocateIrp Error!\n");
return STATUS_UNSUCCESSFUL;
};
// 创建事件
KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);
// 创建空文件对象
InitializeObjectAttributes(&objectAttributes, NULL, OBJ_CASE_INSENSITIVE, NULL, NULL);
status = ObCreateObject(KernelMode, *IoFileObjectType, &objectAttributes, KernelMode, NULL, sizeof(FILE_OBJECT), 0, 0, &pFileObject);
if (!NT_SUCCESS(status)){
DbgPrint("ObCreateObject Error[0x%X]\n", status);
return status;
};
// 设置创建的文件对象 FILE_OBJECT
RtlZeroMemory(pFileObject, sizeof(FILE_OBJECT));
pFileObject->Type = IO_TYPE_FILE;
pFileObject->Size = sizeof(FILE_OBJECT);
pFileObject->DeviceObject = RootRealDevice;
pFileObject->Flags = FO_SYNCHRONOUS_IO;
// FILE_OBJECT中的FileName最好动态创建, 否则ObDereferenceObject文件句柄的时候会蓝屏
pFileObject->FileName.Buffer = (PWCHAR)ExAllocatePool(NonPagedPool, ulFileNameMaxSize);
pFileObject->FileName.MaximumLength = (USHORT)ulFileNameMaxSize;
pFileObject->FileName.Length = pustrFilePath->Length - 4;
RtlZeroMemory(pFileObject->FileName.Buffer, ulFileNameMaxSize);
RtlCopyMemory(pFileObject->FileName.Buffer, &pustrFilePath->Buffer[2], pFileObject->FileName.Length);
DbgPrint("pFileObject->FileName:%wZ\n", &pFileObject->FileName);
KeInitializeEvent(&pFileObject->Lock, SynchronizationEvent, FALSE);
KeInitializeEvent(&pFileObject->Event, NotificationEvent, FALSE);
// 创建权限状态
RtlZeroMemory(&auxAccessData, sizeof(auxAccessData));
status = SeCreateAccessState(&accessData, &auxAccessData, DesiredAccess, IoGetFileObjectGenericMapping());
if (!NT_SUCCESS(status)){
IoFreeIrp(pIrp);
ObDereferenceObject(pFileObject);
DbgPrint("SeCreateAccessState Error[0x%X]\n", status);
return status;
};
// 设置安全内容 IO_SECURITY_CONTEXT
ioSecurityContext.SecurityQos = NULL;
ioSecurityContext.AccessState = &accessData;
ioSecurityContext.DesiredAccess = DesiredAccess;
ioSecurityContext.FullCreateOptions = 0;
// 设置IRP
RtlZeroMemory(IoStatusBlock, sizeof(IO_STATUS_BLOCK));
pIrp->MdlAddress = NULL;
pIrp->AssociatedIrp.SystemBuffer = EaBuffer;
pIrp->Flags = IRP_CREATE_OPERATION | IRP_SYNCHRONOUS_API;
pIrp->RequestorMode = KernelMode;
pIrp->UserIosb = IoStatusBlock;
pIrp->UserEvent = &kEvent;
pIrp->PendingReturned = FALSE;
pIrp->Cancel = FALSE;
pIrp->CancelRoutine = NULL;
pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
pIrp->Tail.Overlay.AuxiliaryBuffer = NULL;
pIrp->Tail.Overlay.OriginalFileObject = pFileObject;
// 获取下一个IRP的IO_STACK_LOCATION并设置
pIoStackLocation = IoGetNextIrpStackLocation(pIrp);
pIoStackLocation->MajorFunction = IRP_MJ_CREATE;
pIoStackLocation->DeviceObject = RootDeviceObject;
pIoStackLocation->FileObject = pFileObject;
pIoStackLocation->Parameters.Create.SecurityContext = &ioSecurityContext;
pIoStackLocation->Parameters.Create.Options = (CreateDisposition << 24) | CreateOptions;
pIoStackLocation->Parameters.Create.FileAttributes = (USHORT)FileAttributes;
pIoStackLocation->Parameters.Create.ShareAccess = (USHORT)ShareAccess;
pIoStackLocation->Parameters.Create.EaLength = EaLength;
// 设置完成实例, 以便通知IRP处理完成, 释放资源
IoSetCompletionRoutine(pIrp, MyCompleteRoutine, NULL, TRUE, TRUE, TRUE);
// 发送IRP
status = IoCallDriver(RootDeviceObject, pIrp);
// 等待IRP的处理
if (STATUS_PENDING == status)
KeWaitForSingleObject(&kEvent, Executive, KernelMode, TRUE, NULL);
// 判断IRP处理结果
status = IoStatusBlock->Status;
if (!NT_SUCCESS(status)){
ObDereferenceObject(pFileObject);
DbgPrint("IRP FAILED!\n");
return status;
};
InterlockedIncrement(&pFileObject->DeviceObject->ReferenceCount);
if (pFileObject->Vpb)
InterlockedIncrement(&pFileObject->Vpb->ReferenceCount);
// 返回文件对象
*ppFileObject = pFileObject;
return status;
};
// 文件遍历
// ZwQueryDirectoryFile
NTSTATUS IrpQueryDirectoryFile(IN PFILE_OBJECT pFileObject, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass, IN PUNICODE_STRING FileName OPTIONAL){
NTSTATUS status = STATUS_SUCCESS;
PIRP pIrp = NULL;
KEVENT kEvent = { 0 };
PIO_STACK_LOCATION pIoStackLocation = NULL;
PDEVICE_OBJECT pDevObj = NULL;
// 判断参数是否有效
if ((NULL == pFileObject) || (NULL == pFileObject->Vpb) || (NULL == pFileObject->Vpb->DeviceObject))
return STATUS_UNSUCCESSFUL;
// 获取设备对象
pDevObj = pFileObject->Vpb->DeviceObject;
// 创建IRP
pIrp = IoAllocateIrp(pDevObj->StackSize, FALSE);
if (NULL == pIrp)
return STATUS_UNSUCCESSFUL;
// 创建事件
KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);
// 设置IRP
RtlZeroMemory(FileInformation, Length);
pIrp->UserEvent = &kEvent;
pIrp->UserIosb = IoStatusBlock;
pIrp->UserBuffer = FileInformation;
pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
pIrp->Tail.Overlay.OriginalFileObject = pFileObject;
pIrp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
// 获取下一个IRP的IO_STACK_LOCATION并设置
pIoStackLocation = IoGetNextIrpStackLocation(pIrp);
pIoStackLocation->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
pIoStackLocation->MinorFunction = IRP_MN_QUERY_DIRECTORY;
pIoStackLocation->FileObject = pFileObject;
pIoStackLocation->Flags = SL_RESTART_SCAN;
pIoStackLocation->Parameters.QueryDirectory.Length = Length;
pIoStackLocation->Parameters.QueryDirectory.FileName = FileName;
pIoStackLocation->Parameters.QueryDirectory.FileInformationClass = FileInformationClass;
// 设置完成实例, 以便通知IRP处理完成, 释放资源
IoSetCompletionRoutine(pIrp, MyCompleteRoutine, NULL, TRUE, TRUE, TRUE);
// 发送IRP
status = IoCallDriver(pDevObj, pIrp);
// 等待IRP的处理
if (STATUS_PENDING == status)
KeWaitForSingleObject(&kEvent, Executive, KernelMode, FALSE, NULL);
status = IoStatusBlock->Status;
if (!NT_SUCCESS(status))
return status;
return status;
};
// 获取文件的信息
// ZwQueryInformationFile
NTSTATUS IrpQueryInformationFile(IN PFILE_OBJECT pFileObject, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass){
NTSTATUS status = STATUS_SUCCESS;
PIRP pIrp = NULL;
KEVENT kEvent = { 0 };
PIO_STACK_LOCATION pIoStackLocation = NULL;
PDEVICE_OBJECT pDevObj = NULL;
// 判断参数是否有效
if ((NULL == pFileObject) || (NULL == pFileObject->Vpb) || (NULL == pFileObject->Vpb->DeviceObject))
return STATUS_UNSUCCESSFUL;
// 获取设备对象
pDevObj = pFileObject->Vpb->DeviceObject;
// 创建IRP
pIrp = IoAllocateIrp(pDevObj->StackSize, FALSE);
if (NULL == pIrp)
return STATUS_UNSUCCESSFUL;
// 创建事件
KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);
// 设置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;
// 获取下一个IRP的IO_STACK_LOCATION并设置
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;
// 设置完成实例, 以便通知IRP处理完成, 释放资源
IoSetCompletionRoutine(pIrp, MyCompleteRoutine, NULL, TRUE, TRUE, TRUE);
// 发送IRP
status = IoCallDriver(pDevObj, pIrp);
// 等待IRP的处理
if (STATUS_PENDING == status)
KeWaitForSingleObject(&kEvent, Executive, KernelMode, FALSE, NULL);
status = IoStatusBlock->Status;
if (!NT_SUCCESS(status))
return status;
return status;
};
// 设置文件信息
// ZwSetInformationFile
NTSTATUS IrpSetInformationFile(IN PFILE_OBJECT pFileObject, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass){
NTSTATUS status = STATUS_SUCCESS;
PIRP pIrp = NULL;
KEVENT kEvent = { 0 };
PIO_STACK_LOCATION pIoStackLocation = NULL;
PDEVICE_OBJECT pDevObj = NULL;
// 判断参数是否有效
if ((NULL == pFileObject) || (NULL == pFileObject->Vpb) || (NULL == pFileObject->Vpb->DeviceObject))
return STATUS_UNSUCCESSFUL;
// 获取设备对象
pDevObj = pFileObject->Vpb->DeviceObject;
// 创建IRP
pIrp = IoAllocateIrp(pDevObj->StackSize, FALSE);
if (NULL == pIrp)
return STATUS_UNSUCCESSFUL;
// 创建事件
KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);
// 设置IRP
pIrp->UserEvent = &kEvent;
pIrp->UserIosb = IoStatusBlock;
pIrp->AssociatedIrp.SystemBuffer = FileInformation;
pIrp->RequestorMode = KernelMode;
pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
pIrp->Tail.Overlay.OriginalFileObject = pFileObject;
// 获取下一个IRP的IO_STACK_LOCATION并设置
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;
// 设置完成实例, 以便通知IRP处理完成, 释放资源
IoSetCompletionRoutine(pIrp, MyCompleteRoutine, NULL, TRUE, TRUE, TRUE);
// 发送IRP
status = IoCallDriver(pDevObj, pIrp);
// 等待IRP的处理
if (STATUS_PENDING == status)
KeWaitForSingleObject(&kEvent, Executive, KernelMode, FALSE, NULL);
status = IoStatusBlock->Status;
if (!NT_SUCCESS(status))
return status;
return status;
};
// 读文件
// ZwReadFile
NTSTATUS IrpReadFile(IN PFILE_OBJECT pFileObject, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID Buffer, IN ULONG Length, IN PLARGE_INTEGER ByteOffset OPTIONAL){
NTSTATUS status = STATUS_SUCCESS;
PIRP pIrp = NULL;
KEVENT kEvent = { 0 };
PIO_STACK_LOCATION pIoStackLocation = NULL;
PDEVICE_OBJECT pDevObj = NULL;
// 判断参数是否有效
if ((NULL == pFileObject) || (NULL == pFileObject->Vpb) || (NULL == pFileObject->Vpb->DeviceObject))
return STATUS_UNSUCCESSFUL;
// 调整参数
if (NULL == ByteOffset){
if (0 == (FO_SYNCHRONOUS_IO & pFileObject->Flags))
return STATUS_INVALID_PARAMETER;
ByteOffset = &pFileObject->CurrentByteOffset;
};
// 获取设备对象
pDevObj = pFileObject->Vpb->DeviceObject;
// 创建IRP
pIrp = IoAllocateIrp(pDevObj->StackSize, FALSE);
if (NULL == pIrp)
return STATUS_UNSUCCESSFUL;
// 创建事件
KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);
// 设置IRP
RtlZeroMemory(Buffer, Length);
pIrp->MdlAddress = MmCreateMdl(NULL, Buffer, Length);
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并设置
pIoStackLocation = IoGetNextIrpStackLocation(pIrp);
pIoStackLocation->MajorFunction = IRP_MJ_READ;
pIoStackLocation->MinorFunction = IRP_MN_NORMAL;
pIoStackLocation->DeviceObject = pDevObj;
pIoStackLocation->FileObject = pFileObject;
pIoStackLocation->Parameters.Read.Length = Length;
pIoStackLocation->Parameters.Read.ByteOffset = *ByteOffset;
// 设置完成实例, 以便通知IRP处理完成, 释放资源
IoSetCompletionRoutine(pIrp, MyCompleteRoutine, NULL, TRUE, TRUE, TRUE);
// 发送IRP
status = IoCallDriver(pDevObj, pIrp);
// 等待IRP的处理
if (STATUS_PENDING == status)
KeWaitForSingleObject(&kEvent, Executive, KernelMode, FALSE, NULL);
status = IoStatusBlock->Status;
if (!NT_SUCCESS(status))
return status;
return status;
};
// 写文件
// ZwWriteFile
NTSTATUS IrpWriteFile(IN PFILE_OBJECT pFileObject, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PVOID Buffer, IN ULONG Length, IN PLARGE_INTEGER ByteOffset OPTIONAL){
NTSTATUS status = STATUS_SUCCESS;
PIRP pIrp = NULL;
KEVENT kEvent = { 0 };
PIO_STACK_LOCATION pIoStackLocation = NULL;
PDEVICE_OBJECT pDevObj = NULL;
// 判断参数是否有效
if ((NULL == pFileObject) || (NULL == pFileObject->Vpb) || (NULL == pFileObject->Vpb->DeviceObject))
return STATUS_UNSUCCESSFUL;
// 调整参数
if (NULL == ByteOffset){
if (0 == (FO_SYNCHRONOUS_IO & pFileObject->Flags))
return STATUS_INVALID_PARAMETER;
ByteOffset = &pFileObject->CurrentByteOffset;
};
// 获取设备对象
pDevObj = pFileObject->Vpb->DeviceObject;
// 创建IRP
pIrp = IoAllocateIrp(pDevObj->StackSize, FALSE);
if (NULL == pIrp)
return STATUS_UNSUCCESSFUL;
// 创建事件
KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);
// 设置IRP
pIrp->MdlAddress = MmCreateMdl(NULL, Buffer, Length);
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并设置
pIoStackLocation = IoGetNextIrpStackLocation(pIrp);
pIoStackLocation->MajorFunction = IRP_MJ_WRITE;
pIoStackLocation->MinorFunction = IRP_MN_NORMAL;
pIoStackLocation->DeviceObject = pDevObj;
pIoStackLocation->FileObject = pFileObject;
pIoStackLocation->Parameters.Write.Length = Length;
pIoStackLocation->Parameters.Write.ByteOffset = *ByteOffset;
// 设置完成实例, 以便通知IRP处理完成, 释放资源
IoSetCompletionRoutine(pIrp, MyCompleteRoutine, NULL, TRUE, TRUE, TRUE);
// 发送IRP
status = IoCallDriver(pDevObj, pIrp);
// 等待IRP的处理
if (STATUS_PENDING == status)
KeWaitForSingleObject(&kEvent, Executive, KernelMode, FALSE, NULL);
status = IoStatusBlock->Status;
if (!NT_SUCCESS(status))
return status;
return status;
};