文件操作
1.文件的创建 对文件的创建或者打开都是通过内核函数ZwCreateFile实现的。和Windows API类似,这个内核函数返回一个文件句柄,文件的所有操作都是依靠这个句柄进行操作的。在文件操作完毕后,要关闭这个文件句柄。 NTSTATUS ZwCreateFile( OUT PHANDLE FileHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, 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 ); FileHandle:返回打开文件的句柄 DesiredAccess: 一般指定为GENERIC_READ 或者 GENERIC_WRITE ObjectAttributes:是OBJECT_ATTRIBUTES结构的地址,该结构包含要打开的文件名。 IoStatusBlock:指向一个IO_STATUS_BLOCK结构体,该结构接收ZwCreateFile操作的结果状态。 AllocationSize:是一个指针,指向一个64位整数,该数指定文件初始分配时的大小、该参数仅关系到创建或重写文件操作。如果忽略它,那么文件长度将从0开始,并随着写入而增长。 FileAttributes:指定新创建文件的属性,一般为0或FILE_ATTRIBUTE_NORMAL ShareAccess:指定文件的共享方式,0或者FILE_SHARE_READ CreateDisposition:指定当文件存在或不存在时,该如何处理 CreateOptions:FILE_SYNCHRONOUS_IO_NONALERT,指定控制打开操作和句柄使用的附加标志位。 EaBuffer:一个指针,指向可选的扩展属性区 EaLength:扩展属性区的长度 要创建的文件的文件名是通过第三个参数传入的。这个参数是一个OBJECT_ATTRIBUTES得结构。DDK提供了对OBJECT_ATTRIBUTES初始化的宏: VOID InitializeObjectAttributes( OUT POBJECT_ATTRIBUTES InitializedAttributes, IN PUNICODE_STRING ObjectName,//文件名 IN ULONG Attributes,//一般为OBJ_CASE_INSENSITIVE,对大小写敏感 IN HANDLE RootDirectory,//一般为NULL IN PSECURITY_DESCRIPTOR SecurityDescriptor //一般为NULL ); 示例代码: [cpp] view plaincopy在CODE上查看代码片派生到我的代码片 VOID TetsCreateFile() { UNICODE_STRING string; RtlInitUnicodeString(&string, L"\\??\\C:\\1.log"); OBJECT_ATTRIBUTES objattr; InitializeObjectAttributes(&objattr, &string, OBJ_CASE_INSENSITIVE, NULL, NULL); HANDLE hFile; IO_STATUS_BLOCK iostatus; NTSTATUS status = ZwCreateFile(&hFile, GENERIC_READ | GENERIC_WRITE, &objattr, &iostatus, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if (!NT_SUCCESS(status)) { KdPrint(("文件创建失败!\n")); } else { KdPrint(("文件创建成功!\n")); } //文件操作 //...... //关闭文件句柄 ZwClose(hFile); } 除了可以用ZwCreateFile函数打开文件,DDK还为我们提供了一个ZwOpenFile函数用来打开文件,以简化文件的打开操作。 NTSTATUS ZwOpenFile( OUT PHANDLE FileHandle, IN ACCESS_MASK DesiredAccess, //打开权限,一般为GENERIC_ALL IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG ShareAccess, IN ULONG OpenOptions//打开选项,一般为FILE_SYNCHRONOUS_IO_NONALERT ); 2.获取或修改文件属性 获取和修改文件属性,包括获取文件大小,获取或修改文件指针位置,获取或修改文件名,获取或修改文件属性(只读属性,隐藏属性),获取或修改文件创建,修改日期。 NTSTATUS ZwSetInformationFile( IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass ); NTSTATUS ZwQueryInformationFile( IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass ); FileInformation:依据FileInformationClass不同而不同。 Length:FileInformation数据的长度 FileInformationClass:描述修改属性的类型 (1) 当FileInformationClass 是FileStandardInformation 时,输入和输出数据是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; (2) 当FileInformationClass 是FileBasicInformation 时,输入和输出数据是FILE_BASIC_INFORMATION结构体,描述文件的基本信息。 typedef struct FILE_BASIC_INFORMATION { LARGE_INTEGER CreationTime; LARGE_INTEGER LastAccessTime; LARGE_INTEGER LastWriteTime; LARGE_INTEGER ChangeTime; ULONG FileAttributes; //文件属性 } FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; (3) 当FileInformationClass 是FileNameInformation 时,输入和输出数据是FILE_NAME_INFORMATION结构体,描述文件名信息。 typedef struct _FILE_NAME_INFORMATION { ULONG FileNameLength; //文件名长度 WCHAR FileName[1]; //文件名 } FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION; (4) 当FileInformationClass 是FilePositionInformation 时,输入和输出数据是FILE_POSITION_INFORMATION结构体,描述文件指针位置信息。 typedef struct FILE_POSITION_INFORMATION { LARGE_INTEGER CurrentByteOffset; //代表当期文件指针为止 } FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION; 示例代码: [cpp] view plaincopy在CODE上查看代码片派生到我的代码片 VOID TetsFile() { UNICODE_STRING string; RtlInitUnicodeString(&string, L"\\??\\C:\\1.log"); OBJECT_ATTRIBUTES objattr; InitializeObjectAttributes(&objattr, &string, OBJ_CASE_INSENSITIVE, NULL, NULL); HANDLE hFile; IO_STATUS_BLOCK iostatus; //打开文件 NTSTATUS status = ZwCreateFile(&hFile, GENERIC_READ, &objattr, &iostatus, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if (!NT_SUCCESS(status)) { KdPrint(("文件打开失败!\n")); } else { KdPrint(("文件打开成功!\n")); FILE_BASIC_INFORMATION fbi; //查询文件基本信息 status = ZwQueryInformationFile(hFile, &iostatus, &fbi, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); if (NT_SUCCESS(status)) { KdPrint(("查询文件属性成功!\n")); } //设置文件只读属性 fbi.FileAttributes |= FILE_ATTRIBUTE_READONLY; status = ZwSetInformationFile(hFile, &iostatus, &fbi, sizeof(FILE_BASIC_INFORMATION),FileBasicInformation); if (NT_SUCCESS(status)) { KdPrint(("设置文件只读属性成功!\n")); } //关闭文件句柄 ZwClose(hFile); } } 3.文件的写操作 NTSTATUS ZwWriteFile( IN HANDLE FileHandle, IN HANDLE Event OPTIONAL, //一般设为NULL IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, //一般设为NULL IN PVOID ApcContext OPTIONAL, //一般设为NULL OUT PIO_STATUS_BLOCK IoStatusBlock, //记录实际写的字节数 IN PVOID Buffer, //从这个缓冲区中开始往文件里写 IN ULONG Length, //准备写多少字节 IN PLARGE_INTEGER ByteOffset OPTIONAL, //从文件的多少偏移开始写 IN PULONG Key OPTIONAL //一般设为NULL ); IoStatusBlock:IoStatusBlock.Information记录实际写了多少字节。 示例代码: [cpp] view plaincopy在CODE上查看代码片派生到我的代码片 #define BUFFER_SIZE 1024 #pragma INITCODE VOID TetsFile() { UNICODE_STRING string; RtlInitUnicodeString(&string, L"\\??\\C:\\1.log"); OBJECT_ATTRIBUTES objattr; InitializeObjectAttributes(&objattr, &string, OBJ_CASE_INSENSITIVE, NULL, NULL); HANDLE hFile; IO_STATUS_BLOCK iostatus; //打开文件 NTSTATUS status = ZwCreateFile(&hFile, GENERIC_WRITE, &objattr, &iostatus, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); //分配Buffer空间 PUCHAR pBuffer = (PUCHAR)ExAllocatePool(PagedPool, BUFFER_SIZE); RtlFillMemory(pBuffer, BUFFER_SIZE, 'A'); //写文件 status = ZwWriteFile(hFile, NULL, NULL, NULL, &iostatus, pBuffer, BUFFER_SIZE, NULL, NULL); LARGE_INTEGER ByteOffset; ByteOffset.QuadPart = 1024i64; //设置文件指针偏移 RtlFillMemory(pBuffer, BUFFER_SIZE, 'B'); status = ZwWriteFile(hFile, NULL, NULL, NULL, &iostatus, pBuffer, BUFFER_SIZE, &ByteOffset, NULL); //关闭文件句柄 ZwClose(hFile); //释放内存 ExFreePool(pBuffer); } 4.文件的读操作 NTSTATUS ZwReadFile( IN HANDLE FileHandle, IN HANDLE Event OPTIONAL, IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, IN PVOID ApcContext OPTIONAL, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID Buffer, IN ULONG Length, IN PLARGE_INTEGER ByteOffset OPTIONAL, IN PULONG Key OPTIONAL ); 如果需要读取整个文件,那么得知道文件的大小,我们可以用ZwQueryInformationFile来实现。 示例代码: [cpp] view plaincopy在CODE上查看代码片派生到我的代码片 #pragma INITCODE VOID TetsFile() { UNICODE_STRING string; RtlInitUnicodeString(&string, L"\\??\\C:\\1.log"); OBJECT_ATTRIBUTES objattr; InitializeObjectAttributes(&objattr, &string, OBJ_CASE_INSENSITIVE, NULL, NULL); HANDLE hFile; IO_STATUS_BLOCK iostatus; //打开文件 NTSTATUS status = ZwCreateFile(&hFile, GENERIC_READ, &objattr, &iostatus, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); //获得文件的大小 FILE_STANDARD_INFORMATION fsi; status = ZwQueryInformationFile(hFile, &iostatus, &fsi, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation); //分配Buffer空间 PUCHAR pBuffer = (PUCHAR)ExAllocatePool(PagedPool, (LONG)fsi.EndOfFile.QuadPart); //读文件 status = ZwReadFile(hFile, NULL, NULL, NULL, &iostatus, pBuffer, (LONG)fsi.EndOfFile.QuadPart, NULL, NULL); KdPrint(("Read %d bytes\n", iostatus.Information)); //关闭文件句柄 ZwClose(hFile); //释放内存 ExFreePool(pBuffer); }