《Windows内核安全与驱动编程》-第四章学习

文件、注册表、线程

4.1 文件操作

4.1.1 使用 OBJECT_ATTRIBUTES

​ 一般打开文件应该传入这个文件的路径。但是内核并不直接接受一个字符串,所以使用者必须首先填写一个 OBJECT_ATTRIBUTES 结构。文档中并没有公开,但是该结构总是被 InitializeObjectAttributes 初始化。

VOID InitializeObjectAttributes(
	OUT POBJECT_ATTRIBUTES InitializedAttributes,
	IN PUNICODE_STRING ObjectName,
	IN	HANDLE RootDirectory,
	IN PSECURITY_DESCRIPTOR SecurityDescriptor);

其中 InitializedAttributes 是要初始化的 OBJECT_ATTRIBUTES 结构的指针。objectName 是对象名字字符串,也就是文件名。

​ 在 Windows 内核中,无论是打开文件、著恶策表键还是打卡设备,都会先调用InitializedAttributes 初始化一个 OBJECT_ATTRIBUTES

Attributes 只需填写 OBJ_CASE_INSENSITIVE OBJ_KERNEL_HANDLE 即可。OBJ_CASE_INSENSITIVE 意味着字符串不区分大小写。OBJ_KERNEL_HANDLE 表明打开的是一个内核句柄。内核举报比应用层句柄使用更方便,可以不受线程和进程的限制,在任何线程中都可以读写。也不需要顾及当前进程是否有权限访问该文件的问题。如果不使用内核句柄,则有时不得不填写后面的 SecurityDescriptor 参数。

RootDirectory 用于相对开的情况,目前省略。传入NULL即可。

SecurityDescriptor 用于设置安全描述符,设置内核句柄时不需要填写。

4.1.2 打开和关闭文件

​ 下面的函数用于打开一个文件。

NTSTATUS ZwCreateFile(
	OUT PHANDLE FileHandle,
	IN ACCESS_MASK DesireAccess,
	IN POBJECT_ATTRIBUTES Object_Attribute,
	OUT PIO_STATUS_BLOCK IoStatusBlock,
	In PLARGE_INTEGER AllocationSize OPTIONAL,
	IN ULONG FileAttributes,
	IN ULONG ShareAccess,
	IN ULONG CreateDisposition,
	IN ULONG CreateOptions,
	IN PVOID EaBuffer OPTIONAL,
	IN ULONG EaLength);

​ 该函数参数异常复杂,一一解释。

FileHandle: 一个句柄的指针。如果函数调用成功,那么打开的文件句柄就保存在这个地址里。

DesireAccess :申请的权限。 有两个宏分别组合了常用的读权限和写权限,分别为 GENERIC_READGENERIC_WRITE。还有一个宏代表全部权限,是 GENERIC_ALL。如果想同步打开文件,要加上 SYNCHRONIZE。不同的权限描述符之间可以用 | (位或) 来组合使用。

Object_Attribute : 对象描述。为 OBJCET_ATTRIBUTES 的结构地址。里面包含了要打开的文件名称,在上一节有介绍。

IoStatusBlock : 该结构在内核开发中经常使用,它往往用于表示一个操作的结果。该结构如下:

typedef struce _IO_STATUS_BLOCK{
    union{
        NTSTATUS Status;
        PVOID Pointer;
    };
    ULONG_PTR Information;
}IO_STATUS_BLOCK,*PIO_STATUS_BLOCK;

​ 在实际的编程中很少会用到 Pointer,一般返回结果在 Status 中,成功则为 STATUS_SUCCESS ; 否则就返回一个错误码,进一步的信息保存在 Information 中。

AllocationSize : 这是一个指向64位整数的指针。该数定义文件初始分配的大小。该参数仅关系到创建或者重写文件操作,可以忽略。如果忽略它那么文件长度从0开始,并随着写入而增长。

FileAttributes : 这个参数控制新建立的文件属性,一般的设置为 0 或者 FILE_ATTRIBUTE_NORMAL 即可。

ShareAccess : 本代码打开这个文件时,允许别的代码同时打开这个文件的所有的权限,所以称为共享访问。一共有三种共享访问的标志可以设置: FILE_SHARE_READFILE_SHARE_WRITEFILE_SHARE_DELETE 。这三种标志可以用 | 来组合使用。

CreateDisposition : 这个参数说明了本次打开文件的意图。可能的选择如下(不能互相组合):

  • FILE_CREATE : 新建文件。如果文件已经存在,则请求失败。
  • FILE_OPEN: 打开文件。如果文件不存在,则请求失败。
  • FILE_OPEN_IF: 如果文件存在则打开,否则重新创建一个文件。
  • FILE_OVERWRITE: 如果文件存在则打开并覆盖,否则重新创建一个。
  • FILE_SUPERSEDE: 如果打开的文件已经存在,生成一个新的文件其他它。如果不存在,则简单的重新创建文件。

CreateOptions : 作者经常使用 FILE_NON_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT。 此时文件被同步的打开。同步打开文件的意义在于,以后每次操作文件时,比如写入文件 调用 ZwWriteFile ,在该函数返回时,文件写操作已经完成了,而不会有返回 STATUS_PENDING (未决) 的情况。在非同步文件的情况下,返回未决是常见的。

​ 如果希望每次读写文件都是直接往磁盘上操作。此时 CreateOption 中应该带标志 FILE_NO_INTERMEDIATE_BUFFERING 。但是要注意,对磁盘的操作必须保证文件每次读写都必须以磁盘扇区大小对齐。(常见的是512字节),否则会返回错误。

直接给出该函数调用的示例:

//要返回的文件句柄
HADNLE file_handle = NULL;
//返回值
NTSTATUS status;
//首先初始化含有文件路径的 OBJECT_ATTRIBUTES
OBJECT_ATTRIBUTES object_attributes;
UNICODE_STRING ufile_name = RTL_CONSTANT_STRING(L"\\??\/C:\\a.dat");
InitializeObjectAttributes(
	&object_attributes,
	&ufile_name,
	OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
	NULL,
	NULL);
//以 FILE_OPEN_IF 方式打开
status = ZwCreateFile(
	&file_handle,
	GENERIC_READ|GENERIC_WRITE,
	&object_attributes,
	&io_status,//这里原文里并没有创建这个参数,应该要创建吧。
	NULL,
	FILE_ATTRIBUTE_NORMAL,
	FILE_SHARE_READ,
	FILE_OPEN_IF,
	FILE_NON_DIRECTORY |
    FILE_RANDOM_ACCESS |
    FILE_SYNCHRONOUS_IO_NONALERT,
    NULL,
    0);

​ 注意路径的写法,并不像是应用层一样直接写 “C:\a.dat”,而是写成 “\??\\C:\\a.dat”。这是因为 ZwCreateFile 使用的是对象路径,而 “C:” 是一个符号链接对象,符号链接对象一般都在 “\??\\” 下。

​ 关闭文件则比较简单,直接使用文件句柄和 ZwClose 函数。

ZwClose(file_handle);
4.1.3 文件读/写操作

​ 打开文件后,最重要的操作是对文件的读写。首先介绍文件的读。

NTSTATUS ZwReadFile(
	IN HANDLE FileHandle,
	I
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值