初探内核下的文件管理技术:内核API
字数 2223 2025-08-20 18:18:17
Windows内核下的文件管理技术:内核API实现
前言
Windows内核下的Rootkit开发技术学习。用户数据通常以文件形式存储在本地磁盘上,Rootkit等恶意软件需要操作文件的功能(增、删、查、改)。文件管理主要有三种方式:
- 基于导出的内核API直接操作文件
- 通过构造I/O请求包(IRP)发送IRP操作文件
- 根据文件系统格式(NTFS)解析硬盘二进制数据
本文重点介绍第一种方式——使用内核API实现文件操作。
内核API概述
内核API是一组从内核组件中输出的函数,主要实现于:
- 内核本身模块(NtOskrnl.exe)
- 其他模块(如hal.dll)
常见内核API前缀:
Ex: 通用执行体函数(如ExAllocatePool)Ke: 通用内核函数(如KeAcquireSpinLock)Io: I/O管理器函数(如IoCompleteRequest)Zw: 原生API包装(如ZwCreateFile)
Zw与Nt系列函数
Nt系列函数(如NtCreateFile)是Windows内核提供的原生API,直接与内核模式交互Zw系列函数是原生API的包装,实现几乎相同但通过不同入口点进入系统- 内核模式调用
Nt函数会检查调用上下文(用户/内核模式) - 调用
Zw函数则直接设置PreviousMode为KernelMode
关键数据结构
OBJECT_ATTRIBUTES结构
用于描述操作系统对象(文件、设备、事件等)属性,传递给如ZwCreateFile、ZwOpenKey等API。
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length; // 结构体大小(字节)
HANDLE RootDirectory; // 对象名称的根目录句柄
PUNICODE_STRING ObjectName; // 对象名称(UNICODE_STRING指针)
ULONG Attributes; // 对象属性标志
PSECURITY_DESCRIPTOR SecurityDescriptor; // 安全描述符(通常NULL)
PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService; // 安全服务质量(通常NULL)
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
常用属性标志:
OBJ_CASE_INSENSITIVE: 名称比较不区分大小写OBJ_KERNEL_HANDLE: 句柄仅内核模式可访问OBJ_OPENIF: 对象存在则打开,否则不失败OBJ_PERMANENT: 创建永久对象(不自动删除)
InitializeObjectAttributes宏
用于初始化OBJECT_ATTRIBUTES结构体:
#define InitializeObjectAttributes(p, n, a, r, s) { \
(p)->Length = sizeof(OBJECT_ATTRIBUTES); \
(p)->RootDirectory = r; \
(p)->Attributes = a; \
(p)->ObjectName = n; \
(p)->SecurityDescriptor = s; \
(p)->SecurityQualityOfService = NULL; \
}
文件操作API详解
1. 文件创建(ZwCreateFile)
用于创建或打开文件对象,也可用于目录操作。
NTSTATUS ZwCreateFile(
PHANDLE FileHandle, // 接收文件句柄的指针
ACCESS_MASK DesiredAccess, // 访问类型(读/写/执行等)
POBJECT_ATTRIBUTES ObjectAttributes, // 已初始化的OBJECT_ATTRIBUTES
PIO_STATUS_BLOCK IoStatusBlock, // I/O状态块指针
PLARGE_INTEGER AllocationSize, // 文件分配大小
ULONG FileAttributes, // 文件属性
ULONG ShareAccess, // 共享模式
ULONG CreateDisposition, // 创建方式
ULONG CreateOptions, // 创建选项
PVOID EaBuffer, // 扩展属性缓冲区(通常NULL)
ULONG EaLength // EaBuffer长度
);
内核模式创建文件步骤
- 初始化
UNICODE_STRING结构(文件路径) - 设置
OBJECT_ATTRIBUTES结构体 - 调用
ZwCreateFile - 操作完成后用
ZwClose关闭句柄
示例代码:
void CreateFileTest() {
NTSTATUS status;
HANDLE hFile;
OBJECT_ATTRIBUTES objAttr;
IO_STATUS_BLOCK ioStatusBlock;
UNICODE_STRING fileName;
// 初始化UNICODE_STRING
RtlInitUnicodeString(&fileName, L"\\??\\C:\\path\\MyFile.txt");
// 初始化OBJECT_ATTRIBUTES
InitializeObjectAttributes(&objAttr, &fileName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
// 调用ZwCreateFile
status = ZwCreateFile(&hFile, GENERIC_WRITE | GENERIC_READ, &objAttr,
&ioStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN_IF,
FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (NT_SUCCESS(status)) {
DbgPrint("File created/opened successfully.\n");
ZwClose(hFile);
} else {
DbgPrint("Failed to create/open file. Status: 0x%X\n", status);
}
}
注意事项:
- 文件路径需包含
\\??\\前缀(内核符号链接) FILE_OPEN_IF标志:存在则打开,不存在则创建- 驱动需在测试模式下加载,VS需用x64生成
2. 文件删除(ZwDeleteFile)
删除指定文件:
NTSTATUS ZwDeleteFile(
_In_ POBJECT_ATTRIBUTES ObjectAttributes
);
3. 获取文件信息(ZwQueryInformationFile)
获取文件大小等信息:
NTSTATUS ZwQueryInformationFile(
[in] HANDLE FileHandle, // 文件句柄
[out] PIO_STATUS_BLOCK IoStatusBlock, // I/O状态块
[out] PVOID FileInformation, // 接收信息的缓冲区
[in] ULONG Length, // 缓冲区大小
[in] FILE_INFORMATION_CLASS FileInformationClass // 信息类型
);
常用信息类型:
FileBasicInformation: 基本文件信息FileStandardInformation: 标准文件信息(含大小)FilePositionInformation: 文件指针位置
FILE_STANDARD_INFORMATION结构
typedef struct _FILE_STANDARD_INFORMATION {
LARGE_INTEGER AllocationSize; // 分配大小
LARGE_INTEGER EndOfFile; // 实际大小
ULONG NumberOfLinks; // 硬链接数
BOOLEAN DeletePending; // 是否标记为删除
BOOLEAN Directory; // 是否为目录
} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION;
4. 文件读写(ZwReadFile/ZwWriteFile)
NTSTATUS ZwReadFile(
HANDLE FileHandle, // 文件句柄
HANDLE Event, // 可选事件句柄
PIO_APC_ROUTINE ApcRoutine, // 可选APC例程
PVOID ApcContext, // 可选APC上下文
PIO_STATUS_BLOCK IoStatusBlock,// I/O状态块
PVOID Buffer, // 数据缓冲区(读取)
ULONG Length, // 要读取的字节数
PLARGE_INTEGER ByteOffset, // 读取位置
PULONG Key // 关联键(通常NULL)
);
NTSTATUS ZwWriteFile(
// 参数同ZwReadFile,但Buffer为要写入的数据
);
5. 文件重命名(ZwSetInformationFile)
NTSTATUS ZwSetInformationFile(
_In_ HANDLE FileHandle,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_In_ PVOID FileInformation,
_In_ ULONG Length,
_In_ FILE_INFORMATION_CLASS FileInformationClass
);
使用FileRenameInformation信息类型和FILE_RENAME_INFORMATION结构:
typedef struct _FILE_RENAME_INFORMATION {
BOOLEAN ReplaceIfExists; // 存在是否替换
HANDLE RootDirectory; // 根目录句柄
ULONG FileNameLength; // 文件名长度
WCHAR FileName[1]; // 文件名(灵活数组成员)
} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;
内存分配:
- 使用
ExAllocatePoolWithTag动态分配内存 - 内存大小计算:
sizeof(FILE_RENAME_INFORMATION) + FileNameLength - 完成后用
ExFreePoolWithTag释放
6. 文件遍历(ZwQueryDirectoryFile)
枚举目录内容:
NTSTATUS ZwQueryDirectoryFile(
HANDLE FileHandle, // 目录句柄
HANDLE Event, // 可选事件
PIO_APC_ROUTINE ApcRoutine, // 可选APC例程
PVOID ApcContext, // 可选APC上下文
PIO_STATUS_BLOCK IoStatusBlock,// I/O状态块
PVOID FileInformation, // 文件信息缓冲区
ULONG Length, // 缓冲区长度
FILE_INFORMATION_CLASS FileInformationClass, // 信息类型
BOOLEAN ReturnSingleEntry, // 是否只返回单个条目
PUNICODE_STRING FileName, // 文件名掩码(如*.txt)
BOOLEAN RestartScan // 是否从头重新扫描
);
常用信息类型:
FileDirectoryInformation: 基本目录信息FileFullDirectoryInformation: 扩展目录信息FileBothDirectoryInformation: 包含短文件名
FILE_DIRECTORY_INFORMATION结构
typedef struct _FILE_DIRECTORY_INFORMATION {
ULONG NextEntryOffset; // 下一条目偏移(0表示最后)
ULONG FileIndex; // 文件索引号
LARGE_INTEGER CreationTime; // 创建时间
LARGE_INTEGER LastAccessTime; // 最后访问时间
LARGE_INTEGER LastWriteTime; // 最后写入时间
LARGE_INTEGER ChangeTime; // 最后修改时间
LARGE_INTEGER EndOfFile; // 文件大小
LARGE_INTEGER AllocationSize; // 分配大小
ULONG FileAttributes; // 文件属性
ULONG FileNameLength; // 文件名长度
WCHAR FileName[1]; // 文件名(灵活数组成员)
} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;
内存分配API
ExAllocatePoolWithTag
PVOID ExAllocatePoolWithTag(
[in] POOL_TYPE PoolType, // 池类型
[in] SIZE_T NumberOfBytes, // 字节数
[in] ULONG Tag // 池标记
);
常用池类型:
NonPagedPool: 非分页池(任意IRQL可访问)PagedPool: 分页池(IRQL<=APC_LEVEL)NonPagedPoolNx: 非分页池(禁止执行代码)
ExAllocatePool2 (Win10 2004+)
新版本替代函数:
PVOID ExAllocatePool2(
POOL_FLAGS PoolFlags, // 池标志
SIZE_T NumberOfBytes, // 字节数
ULONG Tag // 池标记
);
特点:
- 默认初始化内存为零
- 更丰富的参数控制
总结
本文详细介绍了Windows内核模式下使用内核API进行文件操作的技术,包括:
- 文件创建/打开(
ZwCreateFile) - 文件删除(
ZwDeleteFile) - 文件信息查询(
ZwQueryInformationFile) - 文件读写(
ZwReadFile/ZwWriteFile) - 文件重命名(
ZwSetInformationFile) - 目录遍历(
ZwQueryDirectoryFile)
这些技术是Rootkit和内核驱动开发中文件操作的基础,理解这些API和数据结构对于开发内核级文件管理功能至关重要。