文件读写程序分为4个函数,分别是DriverUnload()、DriverEntry()、CreateFileTest()和OpenFileTest()。这四个函数的作用很明确,DriverUnload()是卸载例程,DriverEntry()是驱动的入口,CreateFileTest()用于新建文件,OpenFileTest()用于打开已建立的文件和阅读。书面功能。1、文件的创建、打开和关闭文件的创建或打开是通过内核驱动程序中的内核函数ZwCreateFile()来操作的。与Win32API类似,返回的文件句柄将作为参数接收。它的返回值是一个状态码,表示操作是否成功。ZwCreateFile()函数的定义如下:NTSTATUSZwCreateFile(__outPHANDLEFileHandle,__inACCESS_MASKDesiredAccess,__inPOBJECT_ATTRIBUTESObjectAttributes,__outPIO_STATUS_BLOCKIoStatusBlock,__in_optPLARGE_INTEGERAllocationSize,__inULONGFileAttributes,__inULONGShareAccess,__inULONGCreateDisposition,__inULONGCreateOptions,__in_optPVOIDEaBuffer,__inULONGEaLength);参数介绍如下。FileHandle:Usedtoreceivethefilehandleaftercreatingthefile.DesiredAccess:文件打开操作的描述,读或写,一般指定为GENERIC_READ或GENERIC_WRITE;此参数与CreateFile()函数中的参数相同。ObjectAttributes:指向包含要创建或打开的文件的名称的OBJECT_ATTRIBUTES结构的指针。IoStatusBlock:指向IO_STATUS_BLOCK结构的指针,用于接收操作结果的状态。AllocationSize:该参数指向一个64位整数,用于文件的初始分配大小。FileAttributes:通常为FILE_ATTRIBUTE_NORMAL,该参数与CreateFile()函数中的参数相同。ShareAccess:指定文件的共享方式,可以指定为FILE_SHARE_READ、FILE_SHARE_WRITE或FILE_SHARE_DELETE。此参数与CreateFile()函数中的参数相同。CreateDisposition:描述本次调用ZwCreateFile()函数的意图,可以指定为FILE_CREATE、FILE_OPEN、FILE_OPEN_IF等。)写文件时的函数,当ZwWriteFile()调用返回时,文件写操作已经完成。EaBuffer:该参数表示指向可选扩展属性区的指针,通常为NULL。EaLength:该参数表示扩展属性区的长度,一般为0。ZwCreateFile()函数的第3个参数是一个指向OBJECT_ATTRIBUTES的结构体,该结构体的定义如下:typedefstruct_OBJECT_ATTRIBUTES{ULONGLength;HANDLERootDirectory;PUNICODE_STRINGObjectName;ULONGAttributes;PVOIDSecurityDescriptor;PVOIDSecurityQualityOfService;}OBJECT_ATTRIBUTES,*POBJECT_ATTRIBUTES;typedefCONSTOBJECT_ATTRIBUTES*PCOBJECT_ATTRIBUTES;该结构body通常不需要用户一一初始化,而是使用InitializeObjectAttributes()函数进行初始化。该函数的定义如下:参数与OBJECT_ATTRIBUTES结构的成员变量相同。InitializeObjectAttributes()函数的参数说明如下。InitializeAttributes:指向OBJECT_ATTRIBUTES结构的指针。ObjectName:对象名称,由UNICODE_STRING描述,对于ZwCreateFile()函数,这被指定为文件名。属性:一般设置为OBJ_CASE_INSENSITIVE,表示名称字符串不区分大小写。RootDirectory:一般设置为NULL。SecurityDescriptor:用来设置安全描述符,一般设置为NULL。ObjectName必须用UNICODE_STRING类型描述。UNICODE_STRING是内核为宽字符串封装的数据结构。这个结构体的定义如下:typedefstruct_UNICODE_STRING{USHORTLength;USHORTMaximumLength;PWSTRBuffer;}UNICODE_STRING,*PUNICODE_STRING;结构成员说明如下。Length:字符串的参数,单位是byte,如果是N个字符,那么Length的值就是N个字符的2倍。MaximumLength:整个字符缓冲区的最大长度,以字节为单位。缓冲区:指向缓冲区的指针。对于UNICODE_STRING类型的字符串,也可以使用KdPrint()进行调试输出,输出方式类似如下:UNICODE_STRINGuniString;KdPrint(("%wZ",&uniString));UNICODE_STRING类型的字符串在使用前需要进行初始化,初始化有两种方法:一种是使用内核函数RtlInitUnicodeString()进行初始化,另一种是自行申请内存空间进行初始化。通常使用第一种方法。RtlInitUnicodeString()函数定义如下:VOIDRtlInitUnicodeString(INOUTPUNICODE_STRINGDestinationString,INPCWSTRSourceString);参数说明如下。DestinationString:指向要初始化的UNICODE_STRING字符串的指针。SourceString:字符串的内容。在将第二个参数传递给InitializeObjectAttributes()函数时,需要指定的文件名是一个符号链接。在应用层下,描述一个文件的完整路径是“c:\a.txt”;而在内核下,描述方式是“\??\c:\a.txt”。在内核模式下,符号链接以“\??\”(或“\DosDevices\”)开头;在用户模式下使用符号链接时,它以“\\.\”开头。上面介绍的ZwCreateFile()函数不仅可以创建文件,还可以打开文件。但是因为它的参数太多,所以在内核函数中专门提供了一个打开文件的函数ZwOpenFile(),定义如下:相当于ZwCreateFile()函数的简化版,只用于打开文件,其参数使用方法与ZwCreateFile()函数相同,这里不再赘述。使用内核函数ZwClose()关闭文件句柄,其定义如下:NTSTATUSZwClose(INHANDLEHandle);该函数只包含一个参数,即打开文件的句柄。除了关闭文件句柄外,该函数还可以关闭其他类型资源的句柄,例如注册表句柄。2、文件相关操作文件相关操作主要介绍四个内核函数,分别是ZwReadFile()、ZwWriteFile()、ZwQueryInformationFile()和ZwSetInformationFile()。示例代码实现了对文件的读写操作,判断打开的文件是否为目录,获取文件长度,设置文件指针。先看ZwQueryInformationFile()和ZwSetInformationFile()这两个函数的定义。ZwQueryInformationFile()函数定义如下:参数说明如下。FileHandle:要打开的文件句柄。IoStatusBlock:返回设置的状态。FileInformation:因FileInformationClass而异。长度:FileInformation数据的长度。FileInformationClass:描述了要获取的属性类型。ZwSetInformationFile()函数的定义如下:ZwSetInformationFile()函数的参数与ZwQueryInformationFile()函数的参数几乎相同,只是两个函数的第三个参数略有不同。不同的是它是ZwQueryInformationFile()的输出参数和ZwSetInformationFile()的输入参数。在这里要小心。对于ZwQueryInformationFile()和ZwSetInformationFile()这两个函数,第五个参数决定了要读取或设置的属性类型,第三个参数根据第五个参数接受或传递相应的值。两个函数的第五个参数常用的值有三种,分别是FileStandardInformation、FileBasicInformation、FilePositionInformation。每种类型对应不同的结构,这些结构被ZwQueryInformationFile()和ZwSetInformationFile()函数的第三个参数使用。FileStandardInformation对应的结构定义如下:typedefstructFILE_STANDARD_INFORMATION{LARGE_INTEGERAllocationSize;//为文件分配的大小(占用簇所需的大小)LARGE_INTEGEREndOfFile;//从文件末尾算起的字节数ULONGNumberOfLinks;//如何许多链接文件BOOLEANDeletePending;//是否要删除BOOLEANDirectory;//是否是目录}FILE_STANDARD_INFORMATION,*PFILE_STANDARD_INFORMATION;FileBasicInformation对应的结构体定义如下://修改时间ULONGFileAttributes;//文件属性}FILE_BASIC_INFORMATION,*PFILE_BASIC_INFORMATION;FilePositionInformation对应的结构体定义如下:typedefstructFILE_POSITION_INFORMATION{LARGE_INTEGERCurrentByteOffset;//当前文件指针位置}FILE_POSITION_INFORMATION的第5个参数,*PFILE_POSITION_INFORMATION;理解了参数之后,就可以知道第四个参数的值,也就是第三个参数的大小。LARGE_INTEGER这个数据类型在上面的结构中被广泛使用,其实就是一个联合体。LARGE_INTEGER的定义如下:该结构主要用于表示64位整数类型,通常使用其QuadPart成员。ZwReadFile()函数的定义如下:NTSTATUSZwReadFile(INHANDLEFileHandle,INHANDLEEventOPTIONAL,INPIO_APC_ROUTINEApcRoutineOPTIONAL,INPVOIDApcContextOPTIONAL,OUTPIO_STATUS_BLOCKIOStatusBlock,OUTPVOIDBuffer,INULONGLength,INPLARGE_INTEGERByteOffsetLOOPTIONAL,INPLARGE_INTEGERByteOffsetLOOPTIONAL,文件打开时使用的Key参数如下:异步完成读取,一般设置为NULLApcRoutine:回调例程,用于异步完成读取,一般设置为NULLApcContext:一般设置为NULLIoStatusBlock:指向IO_STATUS_BLOCK的指针,记录读取的状态操作,IoStatusBlock.Information用于记录读取的字节数Buffer:保存读取文件内容的缓冲区Length:要读取的文件内容的字节数ByteOffset:指定读取的偏移地址content.key:读取文件时的附加信息,一般设置为NULL。ZwWriteFile()函数的定义如下:NTSTATUSZwWriteFile(INHANDLEFileHandle,INHANDLEEventOPTIONAL,INPIO_APC_ROUTINEApcRoutineOPTIONAL,INPVOIDApcContextOPTIONAL,OUTPIO_STATUS_BLOCKIoStatusBlock,INPVOIDBuffer,INULONGLength,INPLARGE_INTEGERByteOffsetOPTIONAL,INPULONGKeyOPTIONAL);该函数的参数类似于ZwReadFile()函数,Buffer中保存的是欲写入文件内容缓冲。3.内存管理函数文件读写代码中使用了三个内存相关的内核函数,分别是ExAllocatePool()、RtlFillMemory()和ExFreePool()。ExAllocatePool()函数用于申请一块内存空间,其定义如下:PVOIDExAllocatePool(INPOOL_TYPEPoolType,INSIZE_TNumberOfBytes);参数说明如下。PoolType:这个参数是一个枚举值。常用的值有两个,分别是NonPagedPool和PagedPool;前者代表非分页内存,后者代表分页内存;永远不会交换到文件中的虚拟内存称为非分页内存,可以交换到文件中的虚拟内存称为分页内存。NumberOfBytes:表示需要分配的内存大小。这个函数的返回值是一个内存地址。RtlFillMemory()函数用于填充内存,其定义如下:VOIDRtlFillMemory(INVOIDUNALIGNED*Destination,INSIZE_TLength,INUCHARFill);参数说明如下。Desination:填写内存地址的起始位置。长度:填充的长度。Fill:需要填充的字节。ExFreePool()函数用于回收ExAllocatePool()申请的内存空间,其定义如下:VOIDExFreePool(INPVOIDP);这个函数只有一个参数,是一个指向ExAllocatePool()函数分配的内存空间的指针。
