内核下对文件创建和打开都是通过ZwCreateFile,这个内核函数返回一个文件句柄,文件的所有操作都是依靠这个句柄进行操作的。在文件操作完毕后,需要关闭这个句柄。
NTSYSAPI NTSTATUS ZwCreateFile(
PHANDLE FileHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PIO_STATUS_BLOCK IoStatusBlock,
PLARGE_INTEGER AllocationSize,
ULONG FileAttributes,
ULONG ShareAccess,
ULONG CreateDisposition,
ULONG CreateOptions,
PVOID EaBuffer,
ULONG EaLength
);
InitializedAttributes:返回的OBJECT ATTRIBUTES结构。
ObjectName:对象名称,用UNICODE STRING描述,这里设置的是文件名。
Attributes:一般设为OBJ_ CASE JINSENSTTIVE, 对大小写敏感。
另外,文件名必须是符号链接或者是设备名。符号链接的概念,已经在第4章中介绍
过。例如,盘符“c:” 就是一个符号链接。这里应该用“\??\c:” 代替,“c:\1.log”" 要写成
“\??\c:\1.log”。
其中,“\??\c:” 是符号链接,内核会将它转换成设备名“\Device\Harddisk\Volume1”。
#include <ntddk.h>
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
DbgPrint("驱动卸载成功");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegPath)
{
//在C盘创建一个文件
HANDLE hFile = NULL;
OBJECT_ATTRIBUTES objAttr = { 0 };
UNICODE_STRING FileName;
IO_STATUS_BLOCK ioStatus;
NTSTATUS status = 0;
pDriverObject->DriverUnload = DriverUnload;
//路径 C:\1.log 符号名字需要这样写
RtlInitUnicodeString(&FileName,L"\\??\\c:\\1.log");
//初始化对象属性 是一个宏
InitializeObjectAttributes(&objAttr,
&FileName,
OBJ_CASE_INSENSITIVE, //比较对象名时不区分大小写
0,
0);
status = ZwCreateFile( &hFile, //返回来的文件句柄
GENERIC_WRITE,
&objAttr,
&ioStatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN_IF, //打开文件可以使用FILE_OPEN
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
);
if (!NT_SUCCESS(status))
{
DbgPrint("文件创建或者打开失败");
return status;
}
ZwClose(hFile);
return STATUS_SUCCESS;
}
打开文件还可以使用,相比ZwCreateFile,参数更加简化
NTSTATUS
ZwOpenFile (
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG ShareAccess,
IN ULONG OpenOptions
);
FileHandle:返回打开的文件句柄。
DesiredAccess:打开的权限,一般设为GENERIC_ALL。
ObjectAttributes: objectAttributes 结构。
loStatusBlock:指向-一个结构体的指针。该结构体指明打开文件的状态。
ShareAccess :共享的权限。可以是FILE_SHARE_READ或者
FILE_SHARE_WRITE。
OpenOptions:打开选项,一般 设为FILE_SYNCHRONOUS_IO_NONALERT.
返回值:指明文件是否被成打开。
ZwOpenFile(
&hfile,
GENERIC_ALL,
&objectAttributes,
&iostatus,
FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT) ;
获取或修改文件的属性
获取和修改文件属性,包括获取文件大小、获取或修改文件指针位置、获取或修改文
件名、获取或修改文件属性(只读属性、隐藏属性)、获取或修改文件创建、修改日期等。
DDK提供了内核函数ZwSetInformationFile和ZwQueryInformationFile函数来进行获取和
修改文件属性。
设置文件信息
NTSYSAPI NTSTATUS ZwSetInformationFile(
HANDLE FileHandle,
PIO_STATUS_BLOCK IoStatusBlock,
PVOID FileInformation,
ULONG Length,
FILE_INFORMATION_CLASS FileInformationClass
);
FileHandle:文件句柄。
loStatusBlock:返回设置的状态。
FileInformation:依据FileInformationClass不同而不同。作为输入信息。
Length: FileInformation 数据的长度。
FileInformationClass:描述修改属性的类型。
查询文件信息
NTSYSAPI NTSTATUS ZwQueryInformationFile(
HANDLE FileHandle,
PIO_STATUS_BLOCK IoStatusBlock,
PVOID FileInformation,
ULONG Length,
FILE_INFORMATION_CLASS FileInformationClass
);
FileHandle:文件句柄。
loStatusBlock:返回设置的状态。
FileInformation:依据FileInformationClass不同而不同。作为输出信息。
Length: FileInformation 数据的长度。
FileInformationClass:描述修改属性的类型。
这两个函数的参数基本相同。其中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_INPORMATION;
(2)
当FileInformationClass是FileBasicInformation 时,输入和输出的数据是FILE_
BASIC_ INFORMATION(文件基本信息)结构体,描述文件的基本信息。
typedef struct FILE BASIC INPORMATION {
LARGE INTEGER CreationTime; //文件创建时间
LARGE . INTEGER LastAccessTime; //最后 访问时间
LARGE INTEGER LastwriteTime; //最后写时间
LARGE INTEGER ChangeTime ; //修改修改时间
ULONG PileAttributest //文件属性
} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATTON;
其中,时间参数是从一个LARGE_INTEGER的整数,该整数代表从1601年经过多少
个100ns (纳秒)。FileAttributes 描述文件属性。FILE ATTRIBUTE NORMAL描述一般文
件。FILE_ATTRIBUTE_DIRECTORY描述是目录。FILE ATTRIBUTE_READONLY描述
该文件为只读。FILE_ ATTRIBUTE_HIDDEN代表隐含文件。FILE ATTRIBUTE _SYSTEM
代表系统文件。
(3)
当FileInformationClass 是FileNameInformation 时,输入和输出的数据是FILE_NAME_INFORMATION结构体,描述文名信息。
typedef struct FILE_NAME_INFORMATION{
ULONG FileNameLength; //文件名长度
WCHAR FileName[11]; // 文件名
} FILE_NAME_INFORMATTON, *PFILE_NAME_INFORMATION;
(4)
当FileInformationClass 是FilePositionInformation 时,输入和输出的数据是FILE_ POSITION_ INFORMATION结构体,描述文件名信息。
typedef struct FILE_POSITION_INFORMATION{
LARGE_INTEGER CurrentByteOffset;//代表当前文件指针位置
} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION;
查询文件名
#include <ntddk.h>
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
DbgPrint("驱动卸载成功");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegPath)
{
//在C盘创建一个文件
HANDLE hFile = NULL;
OBJECT_ATTRIBUTES objAttr = { 0 };
UNICODE_STRING FileName;
IO_STATUS_BLOCK ioStatus;
NTSTATUS status = 0;
FILE_NAME_INFORMATION FileNameInfo = { 0 };
pDriverObject->DriverUnload = DriverUnload;
RtlInitUnicodeString(&FileName,L"\\??\\c:\\1.log");
//初始化对象属性 主要提供了一个要打开的文件名
InitializeObjectAttributes(&objAttr,
&FileName,
OBJ_CASE_INSENSITIVE, //比较对象名时不区分大小写
0,
0);
//打开文件
status = ZwCreateFile( &hFile,
GENERIC_READ,
&objAttr,&ioStatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_OPEN, //打开文件失败就报错
FILE_SYNCHRONOUS_IO_NONALERT,
0,
0);
if (!NT_SUCCESS(status))
{
DbgPrint("文件打开失败");
return status;
}
//查询文件信息
status=ZwQueryInformationFile(hFile,
&ioStatus,
&FileNameInfo, //根据最后一个参数的不同,这个参数就是不同结构的指针
sizeof(FILE_NAME_INFORMATION), //最后一个参数对应接收的结构体大小。
FileNameInformation);
if (!FileNameInfo.FileName)
{
return STATUS_FILE_INVALID;
}
DbgPrint("文件名是:%S 文件名的长度:%x\n ", FileNameInfo.FileName,FileNameInfo.FileNameLength);
ZwClose(hFile);
return STATUS_SUCCESS;
}
文件写的操作
NTSYSAPI NTSTATUS ZwWriteFile(
HANDLE FileHandle,
HANDLE Event,
PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
PVOID Buffer,
ULONG Length,
PLARGE_INTEGER ByteOffset,
PULONG Key
);
FilcHandle:文件打开的句柄。
Event:很少用到,一般设置为NULL。
ApcRoutine:很少用到,- -般设置为NULL。
ApcContext:很少用到,一般设置为NULL.
loStatusBlock:记录写操作的状态。其中,loStatusBlock.Infomation 记录实际写了
多少字节。
Buffer:从这个缓冲区开始往文件里写。)
Length:准备写多少字节。
ByteOffset:从文件的多少偏移地址开始写。
Key:很少用到,- -般设置为NULL。
#include <ntddk.h>
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
DbgPrint("驱动卸载成功");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegPath)
{
//在C盘创建一个文件
HANDLE hFile = NULL;
OBJECT_ATTRIBUTES objAttr = { 0 };
UNICODE_STRING FileName;
IO_STATUS_BLOCK ioStatus;
NTSTATUS status = 0;
FILE_NAME_INFORMATION FileNameInfo = { 0 };
pDriverObject->DriverUnload = DriverUnload;
RtlInitUnicodeString(&FileName,L"\\??\\c:\\1.log");
//初始化对象属性 主要提供了一个要打开的文件名
InitializeObjectAttributes(&objAttr,
&FileName,
OBJ_CASE_INSENSITIVE, //比较对象名时不区分大小写
0,
0);
//打开文件
status = ZwCreateFile( &hFile,
GENERIC_READ | GENERIC_WRITE,
&objAttr,&ioStatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_OPEN, //打开文件失败就报错
FILE_SYNCHRONOUS_IO_NONALERT,
0,
0);
if (!NT_SUCCESS(status))
{
DbgPrint("文件打开失败");
return status;
}
status=ZwWriteFile( hFile,
NULL,
NULL,
NULL,
&ioStatus,
"zheyangma", //写入的内容 也可以分配内存 然后填充内容
6, //写入的长度
0,
0);
if (!NT_SUCCESS(status))
{
DbgPrint("文件写入失败");
ZwClose(hFile);
return status;
}
ZwClose(hFile);
return STATUS_SUCCESS;
}
文件读取
NTSYSAPI NTSTATUS ZwReadFile(
HANDLE FileHandle,
HANDLE Event,
PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
PVOID Buffer,
ULONG Length,
PLARGE_INTEGER ByteOffset,
PULONG Key
);
练习:
在文件的末尾追加内容
#include <ntddk.h>
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
DbgPrint("驱动卸载成功");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegPath)
{
//在C盘创建一个文件
HANDLE hFile = NULL;
OBJECT_ATTRIBUTES objAttr = { 0 };
UNICODE_STRING FileName;
IO_STATUS_BLOCK ioStatus;
NTSTATUS status = 0;
FILE_NAME_INFORMATION FileNameInfo = { 0 };
FILE_STANDARD_INFORMATION fsi = { 0 };
pDriverObject->DriverUnload = DriverUnload;
RtlInitUnicodeString(&FileName,L"\\??\\c:\\1.log");
//初始化对象属性 主要提供了一个要打开的文件名
InitializeObjectAttributes(&objAttr,
&FileName,
OBJ_CASE_INSENSITIVE, //比较对象名时不区分大小写
0,
0);
//打开文件
status = ZwCreateFile( &hFile,
GENERIC_READ | GENERIC_WRITE,
&objAttr,&ioStatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_OPEN, //打开文件失败就报错
FILE_SYNCHRONOUS_IO_NONALERT,
0,
0);
if (!NT_SUCCESS(status))
{
DbgPrint("文件打开失败");
return status;
}
//查询文件大小
ZwQueryInformationFile(hFile, &ioStatus, &fsi, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation);
//当前指针位置为文件尾。
FILE_POSITION_INFORMATION fpi;
fpi.CurrentByteOffset = fsi.EndOfFile;
//设置文件指针
ZwSetInformationFile(hFile, &ioStatus,&fpi , sizeof(FILE_POSITION_INFORMATION), FilePositionInformation);
//把这个数组的内容追加到文件
UCHAR arr[] = { 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80 };
status = ZwWriteFile(hFile,
NULL,
NULL,
NULL,
&ioStatus,
arr,
17, //写入的长度
0,
0);
if (!NT_SUCCESS(status))
{
DbgPrint("文件写入失败");
ZwClose(hFile);
return status;
}
ZwClose(hFile);
return STATUS_SUCCESS;
}