文件的打开与关闭:
ZwCreateFile用于打开或创建文件,其原型如下:
NTSTATUS ZwCreateFile(
Out PHANDLE FileHandle,
In ACCESS_MASK DesiredAccess,
In POBJECT_ATTRIBUTES ObjectAttributes,
Out PIO_STATUS_BLOCK IoStatusBlock,
In_opt PLARGE_INTEGER AllocationSize,
In ULONG FileAttributes,
In ULONG ShareAccess,
In ULONG CreateDisposition,
In ULONG CreateOptions,
In_reads_bytes_opt(EaLength) PVOID EaBuffer,
In ULONG EaLength
);
FileHandl参数表示句柄的指针。如果这个函数调用返回成功(STATUS_SUCCESS),那么打开的文件句柄就返回在这个地址内。
DesiredAccess参数表示申请的权限。如果打开写文件内容,请使用FILE_WRITE_DATA;如果需要读文件内容,请使用FILE_READ_DATA;如果需要删除文件或者给文件改名,请使用DELETE;如果想设置写文件属性,请使用FILE_WRITE_ATTRIBUTES;反之,设置读文件属性则使用FILE_READ_ATTRIBUTES。这些条件可以用|(位或)来组合。有两个宏分别组合了常用的读权限和常用的写权限,分别为GENERIC_READ和GENERIC_WRITE。还有一个宏代表全部权限,即GENERIC_ALL。此外,如果想同步打开文件,请加上SYNCHRONIZE。
Object_Attribute参数表示对象属性。这个参数在之前注册表那里已经介绍过。
IoStatusBlock也是一个结构。这个结构在内核开发中经常会用到,它往往用于表示一个操作的结果。原型如下:
typedef struct IO_STATUS_BLOCK {
union {
NTSTATUS Status;
PVOID Pointer;
} DUMMYUNIONNAME;
ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
在实际编程中很少会用到Pointer。一般返回的结果在Status中,成功则为STATUS_SUCCESS;否则是一个错误码。进一步的信息在Information中,在不同的情况下返回的Information信息意义不同。针对ZwCreateFile调用的情况,Information的返回值有以下几种可能:
FILE_CREATED:文件被成功地新建了。
FILE_OPENED:文件被打开了。
FILE_OVERWRITTEN:文件被覆盖了。
FILE_SUPERSEDED:文件被替代了。
FILE_EXISTS:文件已存在。
FILE_DOES_NOT_EXIST:文件不存在(因而打开失败了)。
AllocationSize参数是一个指针,指向64位整数,该参数定义了文件初始分配的大小。该参数仅关系到创建或重写文件操作,如果忽略它,那么文件长度从0开始,并随着写入而增长。
FileAttributes参数控制新建立的文件属性,一般地,设置为0或者FILE_ATTRIBUTE_NORMAL即可。
ShareAccess共享权限。一共有三种共享标志可以设置:FILE_SHARE_READ、FILE_SHARE_WRITE和FILE_SHARE DELETE。这三种标志可以用|(位或)来组合。
CreateDisposition参数说明了这次打开的意图。
FILE_CREATE:新建文件。如果文件已经存在,则请求失败。
FILE_OPEN:打开文件。如果文件不存在,则请求失败。
FILE_OPEN_IF:打开或新建文件。如果文件存在,则打开;如果不存在,则新建文件。
FILE_OVERWRITE:覆盖。如果文件存在,则打开并覆盖其内容;如果文件不存在,则请求返回失败。
FILE_OVERWRITE_IF:新建或覆盖。如果要打开的文件已存在,则打开它,并覆盖其内容;如果不存在,则简单地新建文件。
FILE_SUPERSEDE:新建或取代。如果要打开的文件已存在,则生成一个新文件替代之;如果不存在,则简单地生成新文件。
CreateOptions使用FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT。此时文件被同步地打开,而且打开的是文件(而不是目录,创建目录请用FILE_DIRECTORY_ FILE)。所谓同步地打开的意义在于,以后每次操作文件时,比如写入文件,调用ZwWriteFile,在ZwWriteFile返回时,文件写操作已经完成了,而不会有返回STATUS_PENDING的情况。在非同步文件的情况下,返回未决是常见的,此时文件请求没有被完成,使用者需要等待事件来等待请求的完成。当然,好处是使用者可以先去做别的事情。要同步打开,前面的DesiredAccess参数必须含有SYNCHRONIZE。
EaBuffer一般NULL即可
EaLength一般0即可
下面给出一个简单的使用:
VOID FileRW()
{
NTSTATUS st;
HANDLE hFIle;
OBJECT_ATTRIBUTES oa;
IO_STATUS_BLOCK IoSttus;
UNICODE_STRING FileName = RTL_CONSTANT_STRING(L"\??\C:\test.txt");//字符串初始化宏
InitializeObjectAttributes(&oa, &FileName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
st = ZwCreateFile(&hFIle,
GENERIC_ALL,
&oa,
&IoSttus,
NULL,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN_IF,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
NULL, 0);
if (NT_SUCCESS(st))
{
KdPrint((“打开或创建成功\n”));
}
ZwClose(hFIle);
}
在内核中文件的路径不在是以C:\的形式,而是\??\C:\ 这涉及到符号链接的问题
RTL_CONSTANT_STRING是一个宏,这个宏的作用是初始化一个UNICODE_STRING结构体。
关闭文件句柄使用ZwClose函数
文件的读写:
读取文件内容一般使用ZwReadFile,写文件一般使用ZwWriteFile。
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_writes_bytes(Length) PVOID Buffer,
In ULONG Length,
In_opt PLARGE_INTEGER ByteOffset,
In_opt PULONG Key
);
FileHandle参数是前面ZwCreateFile成功后所得到的FileHandle。如果是内核句柄,ZwReadFile和ZwCreateFile并不需要在同一个进程中。句柄是各进程通用的。
Event参数是一个事件对象的句柄,用于异步完成读时。
ApcRoutine参数是回调例程,用于异步完成读时。
IoStatusBlock参数表示返回结果状态。同ZwCreateFile中的同名参数。
Buffer参数是缓冲区。如果读文件内容成功,则内容被读到这个缓冲区里。
Length参数描述缓冲区的长度。这个长度也就是试图读取文件的长度。
ByteOffset参数表示要读取的文件的偏移量,也就是要读取的内容在文件中的位置。一般不要设置为NULL。
Key参数表示读取文件时使用的一种附加信息,一般不使用,设置为NULL。
ZwReadFile为函数返回值,成功的返回值是STATUS_SUCCESS。
ZwWriteFile的参数与ZwReadFile完全相同。
如果需要拷贝文件的话,微软并没有提供直接可使用的API,可以使用ZwCreateFile、ZwReadFile和ZwWriteFile三个函数。来达到拷贝的目的。