还记得我们是如何处理I/O请求的(见前面的章节)。例如,在驱动程序SharingMemory中对IRP_MJ_CREATE和IRP_MJ_CLOSE的处理如下:
本例的驱动程序也大致相同,即将完成创建文件的请求。只有放入IO_STATUS_BLOCK结构体的域中的值会依赖于请求的类型。
因为我们定义了FILE_OPEN_IF标志,通过iosb.Information的值,我们可以知道是该建立新的目录还是因该目录已经存在而将其打开。
我再重复一遍,在内核模式下一定要显式地关闭所有打开的句柄。
如您所见,文件的创建实际上是相同的,只是要去掉FILE_DIRECTORY_FILE标志。而FILE_CREATE标志我将其用于多种情况。它表示只可以创建文件。如果文件已经存在,则对ZwCreateFile会以失败结束。
9.4 文件对象
每一个打开的文件句柄都对应着一个文件对象(file object),在内核内存区中有FILE_OBJECT结构体。
例如,我们可以两次打开同一个文件,但是两次的访问请求却不相同:第一次读(FILE_READ_DATA)而第二次写(FILE_WRITE_DATA)。结果内核会建立两个FILE_OBJECT结构体,每一个都对应于自己相应的文件句柄。但是两个句柄和相对应的两个FILE_OBJECT结构体都对应着同一个磁盘文件。第一个FILE_OBJECT结构体将设置ReadAccess域,第二个则设置WriteAccess域。例如,试图写入第一个句柄指向的文件时,系统会发现域WriteAccess = FALSE并结束请求。
DeviceObject域将包含指向设备对象\Device\HarddiskVolume1的指针,因为这个设备是对\??\c:符号链接,我们创建文件时在文件名中使用了\??\c:。
在读完本文后您可能会进行文件操作的实验并会发现系统是如何填充并管理FILE_OBJECT结构体的。如果在内存中定位它时发生问题,可以使用ObReferenceObjectByHandle函数,形式大致如下:
ObReferenceObjectByHandle向参数pFileObject中返回指向对应于该文件句柄的FILE_OBJECT结构体的指针。这时,引用计数会增一。之后一定要调用ObfDereferenceObject来使其复原。
9.5 写入文件
到这里我们已经有了大小为0目录和文件。该向文件中写点东西了。
借助于ZwCreateFile不止可以创建文件,还可以打开已有的文件(恰好,不只是文件,其它某些对象也是这样)。为此需要指定标志FILE_OPEN。
为了写入文件,需要相应的访问权——使用FILE_WRITE_DATA。
在单元文件中定义了几个常量以用于对文件的一般访问。例如,FILE_GENERIC_WRITE不仅允许向文件中写入数据,还可以更改其属性并添加数据。
显然,当我们写文件,其它的程序不应向该文件写入。使用FILE_SHARE_READ标志,则没有程序能写入或是删除文件,而只能读取文件。
p_Irp^.IoStatus.Status := STATUS_SUCCESS; p_Irp^.IoStatus.Information := 0; IofCompleteRequest(p_Irp, IO_NO_INCREMENT); |
本例的驱动程序也大致相同,即将完成创建文件的请求。只有放入IO_STATUS_BLOCK结构体的域中的值会依赖于请求的类型。
因为我们定义了FILE_OPEN_IF标志,通过iosb.Information的值,我们可以知道是该建立新的目录还是因该目录已经存在而将其打开。
ZwClose(hDirectory); |
我再重复一遍,在内核模式下一定要显式地关闭所有打开的句柄。
RtnCode := ZwCreateFile(@hFile, SYNCHRONIZE, @oa, @iosb, nil, FILE_ATTRIBUTE_NORMAL, 0, FILE_CREATE, FILE_SYNCHRONOUS_IO_NONALERT, nil, 0); |
如您所见,文件的创建实际上是相同的,只是要去掉FILE_DIRECTORY_FILE标志。而FILE_CREATE标志我将其用于多种情况。它表示只可以创建文件。如果文件已经存在,则对ZwCreateFile会以失败结束。
9.4 文件对象
每一个打开的文件句柄都对应着一个文件对象(file object),在内核内存区中有FILE_OBJECT结构体。
TFileObject=packed record wType:Word; Size:Word; DeviceObject:PDeviceObject; DoNotUser1:Pointer; FsContext:Pointer; FsContext2:Pointer; SectionObjectPointer:Pointer; PrivateCacheMap:Pointer; FinalStatus:NTSTATUS; RelatedFileObject:PFileObject; LockOperation:Boolean; DeletePending:Boolean; ReadAccess:Boolean; WriteAccess:Boolean; DeleteAccess:Boolean; SharedRead:Boolean; SharedWrite:Boolean; SharedDelete:Boolean; Flags:Cardinal; FileName:TUnicodeString; CurrentByteOffset:TLargeInteger; Waiters:Cardinal; Busy:Cardinal; LastLock:Pointer; Lock:TKEvent; Event:TKEvent; CompletionContext:Pointer; end; |
例如,我们可以两次打开同一个文件,但是两次的访问请求却不相同:第一次读(FILE_READ_DATA)而第二次写(FILE_WRITE_DATA)。结果内核会建立两个FILE_OBJECT结构体,每一个都对应于自己相应的文件句柄。但是两个句柄和相对应的两个FILE_OBJECT结构体都对应着同一个磁盘文件。第一个FILE_OBJECT结构体将设置ReadAccess域,第二个则设置WriteAccess域。例如,试图写入第一个句柄指向的文件时,系统会发现域WriteAccess = FALSE并结束请求。
DeviceObject域将包含指向设备对象\Device\HarddiskVolume1的指针,因为这个设备是对\??\c:符号链接,我们创建文件时在文件名中使用了\??\c:。
在读完本文后您可能会进行文件操作的实验并会发现系统是如何填充并管理FILE_OBJECT结构体的。如果在内存中定位它时发生问题,可以使用ObReferenceObjectByHandle函数,形式大致如下:
var pFileObject:PFILE_OBJECT; . . . begin RtnCode := ObReferenceObjectByHandle(hFile, FILE_READ_DATA, nil, KernelMode, @pFileObject,nil); if RtnCode = STATUS_SUCCESS then begin {pFileObject指向对应于hFile的FILE_OBJECT} ObfDereferenceObject(pFileObject); end; end; |
ObReferenceObjectByHandle向参数pFileObject中返回指向对应于该文件句柄的FILE_OBJECT结构体的指针。这时,引用计数会增一。之后一定要调用ObfDereferenceObject来使其复原。
9.5 写入文件
到这里我们已经有了大小为0目录和文件。该向文件中写点东西了。
RtnCode := ZwCreateFile(@hFile, FILE_WRITE_DATA + SYNCHRONIZE, @oa, @iosb, nil, 0, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, nil, 0); |
借助于ZwCreateFile不止可以创建文件,还可以打开已有的文件(恰好,不只是文件,其它某些对象也是这样)。为此需要指定标志FILE_OPEN。
为了写入文件,需要相应的访问权——使用FILE_WRITE_DATA。
在单元文件中定义了几个常量以用于对文件的一般访问。例如,FILE_GENERIC_WRITE不仅允许向文件中写入数据,还可以更改其属性并添加数据。
FILE_GENERIC_WRITE = (STANDARD_RIGHTS_WRITE or FILE_WRITE_DATA or FILE_WRITE_ATTRIBUTES or FILE_WRITE_EA or FILE_APPEND_DATA or SYNCHRONIZE); |
显然,当我们写文件,其它的程序不应向该文件写入。使用FILE_SHARE_READ标志,则没有程序能写入或是删除文件,而只能读取文件。
if RtnCode = STATUS_SUCCESS then begin DbgPrint('FileWorks: File openeded'#13#10); g_szData := 'Data can be written to an open file'; RtnCode := ZwWriteFile(hFile, 0, nil, nil, @iosb, |