最新公告
  • 欢迎您光临悠哉网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入我们
  • 网络安全编程:内核下文件读写函数

     

    文件读写程序分为4个函数,分别是DriverUnload()、DriverEntry()、CreateFileTest()和OpenFileTest()。这4个函数的功能非常明确,DriverUnload()是一个卸载例程,DriverEntry()是驱动程序的入口,CreateFileTest()是用来新建文件的,OpenFileTest()是用来打开已建立文件并进行读写的函数。

    1. 文件的创建、打开与关闭

    对于文件的创建或打开,在内核驱动中都是通过内核函数ZwCreateFile()进行操作的。和Win32 API类似,会通过参数接收返回的文件句柄。它的返回值是一个操作是否成功的状态码。ZwCreateFile()函数的定义如下:

    1. NTSTATUS ZwCreateFile(  
    2.  __out PHANDLE FileHandle,  
    3.  __in ACCESS_MASK DesiredAccess,  
    4.  __in POBJECT_ATTRIBUTES ObjectAttributes,  
    5.  __out PIO_STATUS_BLOCK IoStatusBlock,  
    6.  __in_opt PLARGE_INTEGER AllocationSize,  
    7.  __in ULONG FileAttributes,  
    8.  __in ULONG ShareAccess,  
    9.  __in ULONG CreateDisposition,  
    10.  __in ULONG CreateOptions,  
    11.  __in_opt PVOID EaBuffer,  
    12.  __in ULONG EaLength  
    13. );  

    参数介绍如下。

    FileHandle:用来接收创建文件后的文件句柄。

    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 等。

    CreateOptions:通常指定为 FILE_SYNCHRONOUS_IO_NONALERT,表示文件是同步操作,比如在写入文件时,调用 ZwWriteFile()函数,在 ZwWriteFile()调用返回时,文件写操作已经完成。

    EaBuffer:该参数表示一个指针,指向可选的扩展属性区,一般为 NULL。

    EaLength:该参数表示扩展属性区的长度,一般为 0。

    ZwCreateFile()函数的第 3 个参数是一个指向 OBJECT_ATTRIBUTES 的结构体,该结构体的定义如下:

    1. typedef struct _OBJECT_ATTRIBUTES {  
    2.  ULONG Length;  
    3.  HANDLE RootDirectory;  
    4.  PUNICODE_STRING ObjectName;  
    5.  ULONG Attributes;  
    6.  PVOID SecurityDescriptor;  
    7.  PVOID SecurityQualityOfService;  
    8. } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;  
    9. typedef CONST OBJECT_ATTRIBUTES *PCOBJECT_ATTRIBUTES; 

    该结构体通常不需要用户逐个进行初始化,而是使用InitializeObjectAttributes()函数进行初始化,该函数的定义如下:

    1. VOID InitializeObjecttAttributes(  
    2.  OUT POBJECT_ATTRIBUTES InitializedAttributes,  
    3.  IN PUNICODE_STRING ObjectName,  
    4.  IN ULONG Attributes,  
    5.  IN HANDLE RootDirectory,  
    6.  IN PSECURITY_DESCRIPTOR SecurityDescriptor  
    7. );  

    从InitializeObjectAttributes()函数的定义可以看出,其参数与OBJECT_ATTRIBUTES结构体的成员变量相同。InitializeObjectAttributes()函数的参数说明如下。

    InitializeAttributes:指向 OBJECT_ATTRIBUTES 结构体的指针。

    ObjectName:对象名称,用 UNICODE_STRING 描述,对于 ZwCreateFile()函数而言,该处指定为文件名。

    Attributes:一般设置为 OBJ_CASE_INSENSITIVE,意味着名字字符串不区分大小写。

    RootDirectory:一般设置为 NULL。

    SecurityDescriptor:用于设置安全描述符,一般设置为 NULL。

    ObjectName 必须使用 UNICODE_STRING 类型进行描述,UNICODE_STRING 是内核对宽字符串封装的一种数据结构,该结构体的定义如下:

    1. typedef struct _UNICODE_STRING {  
    2.  USHORT Length;  
    3.  USHORT MaximumLength;  
    4.  PWSTR Buffer;  
    5. } UNICODE_STRING, *PUNICODE_STRING; 

    结构体成员说明如下。

    Length:字符串的参数,单位是字节,如果是 N 个字符,那幺 Length 的值为 N 个字符的 2 倍。

    MaximumLength:整个字符缓冲区的最大长度,单位是字节。

    Buffer:缓冲区的指针。

    对于 UNICODE_STRING 类型的字符串,通过 KdPrint()也可以进行调试输出,输出的方式类似如下:

    1. UNICODE_STRING uniString;  
    2. KdPrint(("%wZ", &uniString)); 

    UNICODE_STRING类型的字符串在使用前需要进行初始化,初始化的方法有两种:一种是使用内核函数RtlInitUnicodeString()进行初始化,另一种方式是自行申请内存空间来进行初始化。通常情况下都是用第1种方法。RtlInitUnicodeString()函数的定义如下:

    1. VOID RtlInitUnicodeString(  
    2.  IN OUT PUNICODE_STRING DestinationString,  
    3.  IN PCWSTR SourceString  
    4. );  

    参数说明如下。

    DestinationString:要初始化的 UNICODE_STRING 字符串的指针。

    SourceString:字符串的内容。

    在为InitializeObjectAttributes()函数传递第2个参数时,需要指定的文件名是一个符号链接。在应用层下,描述一个文件的完整路径是“c:\\a.txt”;而在内核下,描述的方式为“\\??\\c:\\a.txt”。符号链接在内核模式下以“\\??\\”(或者是“\\DosDevices\\”)开头;在用户模式下使用符号链接,则以“\\\\.\\”开头。

    上面介绍的ZwCreateFile()函数不但可以创建文件,还可以打开文件。但是由于它的参数过于繁多,因此内核函数中专门提供了一个用于进行文件打开的函数ZwOpenFile(),其定义如下:

    1. NTSTATUS ZwOpenFile(  
    2.  OUT PHANDLE FileHandle,  
    3.  IN ACCESS_MASK DesiredAccess,  
    4.  IN POBJECT_ATTRIBUTES ObjectAttributes,  
    5.  OUT PIO_STATUS_BLOCK IoStatusBlock,  
    6.  IN ULONG ShareAccess,  
    7.  IN ULONG OpenOptions  
    8. );  

    ZwOpenFile()函数相当于一个只用来打开文件的精简版的ZwCreateFile()函数,其各参数使用方法与ZwCreateFile()函数相同,这里不重复介绍。

    文件句柄的关闭使用内核函数ZwClose(),其定义如下:

    1. NTSTATUS ZwClose(IN HANDLE Handle); 

    该函数只包含一个参数,即被打开文件的句柄。该函数除了可以关闭文件句柄以外,还可以关闭其它类型资源的句柄,比如注册表句柄等。

    2. 文件的相关操作

    文件相关的操作主要介绍4个内核函数,分别是ZwReadFile()、ZwWriteFile()、ZwQueryInformationFile()和ZwSetInformationFile()。例子代码中实现了对文件的读写操作,判断打开的文件是否为目录,获取文件的长度和设置文件的指针。

    首先来看ZwQueryInformationFile()和ZwSetInformationFile()两个函数的定义。ZwQueryIn formationFile()函数的定义如下:

    1. NTSTATUS ZwQueryInformationFile(  
    2.  IN HANDLE FileHandle,  
    3.  OUT PIO_STATUS_BLOCK IoStatusBlock,  
    4.  OUT PVOID FileInformation,  
    5.  IN ULONG Length,  
    6.  IN FILE_INFORMATION_CLASS FileInformationClass  
    7. );  

    参数说明如下。

    FileHandle:被打开的文件句柄。

    IoStatusBlock:返回设置的状态。

    FileInformation:依据 FileInformationClass 的不同而不同。

    Length:FileInformation 数据的长度。

    FileInformationClass:描述需获取的属性类型。

    ZwSetInformationFile()函数的定义如下:

    1. NTSTATUS ZwSetInformationFile(  
    2.  IN HANDLE FileHandle,  
    3.  OUT PIO_STATUS_BLOCK IoStatusBlock,  
    4.  IN PVOID FileInformation,  
    5.  IN ULONG Length,  
    6.  IN FILE_INFORMATION_CLASS FileInformationClass  
    7. );  

    ZwSetInformationFile()函数的参数与 ZwQueryInformationFile()函数的参数几乎相同,但是两个函数的第 3 个参数稍有差别,差别在于对 ZwQueryInformationFile()来说是一个输出参数,对于 ZwSetInformationFile()来说是一个输入参数。这里一定要注意。

    对于ZwQueryInformationFile()和ZwSetInformationFile()这两个函数来说,第5个参数决定了要读取或设置的属性的类型,第3个参数根据第5个参数来接受或传递相应的值。

    两个函数的第5个参数的常用值有3种类型,分别是FileStandardInformation、FileBasic Information和FilePositionInformation。每种类型分别又对应不同的结构体,这些结构体则是被ZwQueryInformationFile()和ZwSetInformationFile()函数的第3个参数所用。

    FileStandardInformation对应的结构体定义如下:

    1. typedef struct FILE_STANDARD_INFORMATION {  
    2.  LARGE_INTEGER AllocationSize; // 为文件分配的大小(占用簇所需大小)  
    3.  LARGE_INTEGER EndOfFile; // 距离文件结尾的字节数  
    4.  ULONG NumberOfLinks; // 有多少个链接文件  
    5.  BOOLEAN DeletePending; // 是否准备删除  
    6.  BOOLEAN Directory; // 是否为目录  
    7. } FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION; 

    FileBasicInformation对应的结构体定义如下:

    1. typedef struct FILE_BASIC_INFORMATION {  
    2.  LARGE_INTEGER CreationTime; // 文件创建时间  
    3.  LARGE_INTEGER LastAccessTime; // 最后访问时间  
    4.  LARGE_INTEGER LastWriteTime; // 最后写入时间  
    5.  LARGE_INTEGER ChangeTime; // 修改时间  
    6.  ULONG FileAttributes; // 文件属性  
    7. } FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; 

    FilePositionInformation对应的结构体定义如下:

    1. typedef struct FILE_POSITION_INFORMATION {  
    2.  LARGE_INTEGER CurrentByteOffset; // 当前文件指针位置  
    3. } FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION; 

    明白了第3个参数和第5个参数以后,就可以清楚第4个参数的取值了,该取值是第3个参数的大小。

    上面的结构体中大量使用了LARGE_INTEGER的数据类型,它其实是一个联合体。LARGE_INTEGER的定义如下:

    1. typedef union _LARGE_INTEGER {  
    2.   struct {  
    3.     ULONG LowPart;  
    4.     LONG HighPart;  
    5.   };  
    6.   struct {  
    7.     ULONG LowPart;  
    8.     LONG HighPart;  
    9.   } u;  
    10.   LONGLONG QuadPart;  
    11. } LARGE_INTEGER; 

    该结构体主要是用来表示64位的整数类型,通常使用其QuadPart成员。

    ZwReadFile()函数的定义如下:

    1. NTSTATUS ZwReadFile(  
    2.  IN HANDLE FileHandle,  
    3.  IN HANDLE Event OPTIONAL,  
    4.  IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,  
    5.  IN PVOID ApcContext OPTIONAL,  
    6.  OUT PIO_STATUS_BLOCK IoStatusBlock,  
    7.  OUT PVOID Buffer,  
    8.  IN ULONG Length,  
    9.  IN PLARGE_INTEGER ByteOffset OPTIONAL,  
    10.  IN PULONG Key OPTIONAL  
    11. ); 

    参数说明如下。

    FileHandle:打开文件的句柄。

    Event:用于异步完成读取时,一般设置为 NULL。

    ApcRoutine:回调例程,用于异步完成读取时,一般设置为 NULL。

    ApcContext:一般设置为 NULL。

    IoStatusBlock:指向 IO_STATUS_BLOCK 的指针,记录读取操作的状态,IoStatusBlock.Information 用于记录读取的字节数。

    Buffer:保存读取文件内容的缓冲区。

    Length:准备读取文件内容的字节数。

    ByteOffset:指定读取内容的偏移地址。

    Key:读取文件时的附加信息,一般设置为 NULL。

    ZwWriteFile()函数的定义如下:

    1. NTSTATUS ZwWriteFile(  
    2.  IN HANDLE FileHandle,  
    3.  IN HANDLE Event OPTIONAL,  
    4.  IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,  
    5.  IN PVOID ApcContext OPTIONAL,  
    6.  OUT PIO_STATUS_BLOCK IoStatusBlock,  
    7.  IN PVOID Buffer,  
    8.  IN ULONG Length,  
    9.  IN PLARGE_INTEGER ByteOffset OPTIONAL,  
    10.  IN PULONG Key OPTIONAL  
    11. );  

    该函数的参数类似于ZwReadFile()函数,Buffer中保存的是欲写入文件内容的缓冲区。

    3. 内存管理函数

    文件读写代码中用到了3个内存相关的内核函数,分别是ExAllocatePool()、RtlFillMem ory()和ExFreePool()。

    ExAllocatePool()函数用于申请一块内存空间,其定义如下:

    1. PVOID ExAllocatePool(  
    2.  IN POOL_TYPE PoolType,  
    3.  IN SIZE_T NumberOfBytes  
    4. );  

    参数说明如下。

    PoolType:该参数是一个枚举值,常用的值有两个,分别是 NonPagedPool 和 PagedPool;前者表示非分页内存,而后者表示分页内存;永远不会被交换到文件中的虚拟内存称为非分页内存,可以被交换到文件中的虚拟内存称为分页内存。

    NumberOfBytes:表示需要分配的内存大小。

    该函数的返回值是一个内存地址。

    RtlFillMemory()函数用于填充内存,其定义如下:

    1. VOID RtlFillMemory(  
    2.  IN VOID UNALIGNED *Destination,  
    3.  IN SIZE_T Length,  
    4.  IN UCHAR Fill  
    5. );  

    参数说明如下。

    Desination:填充内存地址的起始位置。

    Length:填充的长度。

    Fill:需要填充的字节。

    ExFreePool()函数用于回收 ExAllocatePool()申请的内存空间,其定义如下:

    1. VOID ExFreePool(IN PVOID P); 

    该函数只有一个参数,是指向ExAllocatePool()函数分配内存空间的指针。

    【编辑推荐】

    1. Steam 增加了对 Mesa 着色器单文件缓存的支持
    2. 炫技!Bug排查大曝光,涉及Linux内核的那种
    3. 微软Windows10 21H1 预览版提升文件资源管理器性能:修复 explorer.exe 高内存占用
    4. Twitter图片可能被滥用来隐藏ZIP、MP3文件
    5. 到2030年,智能农业或将养活85亿人!但网络安全威胁需要重视
    1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
    2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
    3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
    4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
    5. 如有链接无法下载、失效或广告,请联系管理员处理!
    6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
    7. 如遇到加密压缩包,默认解压密码为"www.yoozai.net",如遇到无法解压的请联系管理员!
    悠哉网 » 网络安全编程:内核下文件读写函数

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    悠哉网 WWW.YOOZAI.NET
    悠哉网,用户消费首选的网站,喜欢你就悠哉一下。

    发表评论

    • 1002会员总数(位)
    • 40233资源总数(个)
    • 43本周发布(个)
    • 42 今日发布(个)
    • 377稳定运行(天)

    提供最优质的资源集合

    立即查看 了解详情