1)Windows运用程序的文件与注册表操作进入R0层之后,都有对应的内核函数实现。在windows内核中,无论打开的是文件、注册表或者设备,都需要使用InitializeObjectAttributes来初始化一个OBJECT_ATTRIBUTES结构体:
VOID InitializeObjectAttributes( [out] POBJECT_ATTRIBUTES InitializedAttributes, //OBJECT_ATTRIBUTES的指针 [in] PUNICODE_STRING ObjectName, //对象名字字符串(文件则为路径) [in] ULONG Attributes, //填OBJ_CASE_INSENSITIVE(不区分大小写)|OBJ_KERNEL_HANDLE(内核句柄) [in] HANDLE RootDirectory, //填NULL [in] PSECURITY_DESCRIPTOR SecurityDescriptor //安全描述符,使用内核句柄(OBJ_KERNEL_HANDLE)时忽略 );
2)打开文件(ZwCreateFile)和关闭文件(ZwClose):
NTSTATUS ZwCreateFile( [Out] PHANDLE FileHandle,//文件句柄指针,它指向打开的文件句柄值 [In] ACCESS_MASK DesiredAccess,//申请权限,读写操作,修改文件属性,删除文件等 [In] POBJECT_ATTRIBUTES ObjectAttributes,//对象描述,见八(1) [Out] PIO_STATUS_BLOCK IoStatusBlock,//操作结果结构,成功或失败,失败原因 [In] PLARGE_INTEGER AllocationSize,//很少使用,置为NULL [In] ULONG FileAttributes,//新建立的文件属性,一般为FILE_ATTRUBITE_NORMAL [In] ULONG ShareAccess,//共享访问,本次打开后允许其他对象以什么方式打开 [In] ULONG CreateDisposition,//本次打开意图,如新建或者覆盖 [In] ULONG CreateOptions,//打开选项,如打开文件还是目录,同步打开还是异步打开 [In] PVOID EaBuffer,//置为NULL [In] ULONG EaLength//置为0 );
示例:
HANDLE file_handle = NULL;//要返回的文件句柄 NTSTATUS status;//返回值 //首先初始化含有文件路径的OBJECT_ATTRIBUTES OBJECT_ATTRIBUTES object_attributes; UNICODE_STRING ufile_name = RTL_CONSTANT_STRING(L"\\??\\c:\\a.dat"); //要使用对象路径,“C:”是符号链接对象,一般在“\\??\\” InitializeObjectAttributes( &object_attributes, &ufile_name, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL); //以OPEN_IF方式打开 IO_STATUS_BLOCK io_status; 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|FILE_RANDOM_ACCESS|FILE_SYNCHRONOUS_IO_NONALERT,//打开文件,随机存取打开,同步打开 NULL, );
内核文件句柄的关闭不需要在同一个进程当中,调用ZwClose(file_handle);即可
3)文件读(ZwReadFile)和文件写(ZwWriteFile),方法对称,只不过参数输入输出方向不同。
NTSTATUS ZwReadFile( IN HANDLE FileHandle,//文件句柄,由ZwFileCreate获取 IN HANDLE Event OPTIONAL,//事件,用于异步完成读。同步置位NULL IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,//回调例程,用于异步完成读 IN PVOID ApcContext OPTIONAL, OUT PIO_STATUS_BLOCK IoStatusBlock, //返回结果状态 OUT PVOID Buffer, //缓冲区,读成功则内容在该缓冲区 IN ULONG Length,//描述缓冲区长度,即试图读取文件的长度 IN PLARGE_INTEGER ByteOffset OPTIONAL,//读取内容在文件中的起始偏移量 IN PULONG Key OPTIONAL//附加信息,一般置为NULL );
ZwWriteFile参数与它类似。
4)内核编程读取HKEY_LOCAL_MACHINE时使用路径“\Registry\Machine”,而读取HKEY_USERS时使用“\Registry\User”,由于内核程序不是面向某个“当前用户”的,所以,没有HKEY_CURRENT_USER和HKEY_CLASSES_ROOT对应的路径。
5)打开注册表(ZwOpenKey或者ZwCreateKey)、读注册表(ZwQueryValueKey)和写注册表(ZwSetValueKey):
ZwOpenKey原型: NTSTATUS ZwOpenKey( OUT PHANDLE KeyHandle,//返回的句柄 IN ACCESS_MASK DesiredAccess,//权限,如读、设置、生成子键、枚举子键权限 IN POBJECT_ATTRIBUTES ObjectAttributes//指向OBJECT_ATTRIBUTES ); ZwQueryValueKey原型: NTSTATUS ZwQueryValueKey( IN HANDLE KeyHandle,//句柄,由ZwOpenKey或ZwCreateKey取得 IN PUNICODE_STRING ValueName,//要读取的键名 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,//读取信息的类型 OUT PVOID KeyValueInformation, IN ULONG Length,//传入的KeyValueInformation的长度 OUT PULONG ResultLength//返回实际需要的长度 );
KeyValueInformationClass有3种类型:KeyValueBaseInformation(基础信息:值名和类型)、KeyValueFullInformation(完整信息:值名、类型和数据)和KeyValuePartialInformation(局部信息:类型和数据)。值名是已知的,所以通常是使用KeyValuePartialInformation,此时,KeyValueInformation参数将返回一个KEY_VALUE_PARTIAL_INFOMATION的结构体的指针。它的原型为:
typedef struct _KEY_VALUE_PARTIAL_INFORMATION { ULONG TitleIndex; //忽略 ULONG Type; //数据类型(REG_BINARY(16进制)、REG_DWORD(4字节整数)、REG_SZ(以空结束的Unicode字符串)) ULONG DataLength; //数据长度 UCHAR Data[]; //可变长度的数据 } KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION; ZwSetValueKey原型(写入的键存在怎覆盖,不存在则新建): NTSTATUS ZwSetValueKey( IN HANDLE KeyHandle, IN PUNICODE_STRING ValueName, IN ULONG TitleIndex OPTIONAL,//始终填入0 IN ULONG Type, IN PVOID Data,//要写入的数据起始地址 IN ULONG DataSize//要写入的长度 );
示例:
#define MEM_TAG ‘MyTt’ //读取windws目录,在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion中的SystemRoot键中 //要读取的键名 UNICODE_STRING my_key_name = RTL_CONSTANT_STRING(L"SystemRoot"); //用来试探大小的key_info KEY_VALUE_PARTIAL_INFORMATION key_info; //最后实际用到的key_info指针。内存分配在堆中 PKEY_VALUE_PARTIAL_INFORMATION ac_key_info; ULONG ac_lenth; HANDLE my_key = NULL; NTSTATUS status; //定义要获取的路径 UNICODE_STRING my_key_path = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"); OBJECT_ATTRIBUTES my_obj_attr = {}; //初始化OBJECT_ATTRIBUTES InitializeObjectAttributes( &my_obj_attr, &my_key_path, OBJ_CASE_INSENSITIVE, NULL, NULL); //打开KEY status = ZwOpenKey(&my_key,KEY_READ,&my_obj_attr); if ( !NT_SUCCESS(status) ) { //处理失败 } //读取KEY的值 status = ZwQueryValueKey( my_key, &my_key_name, KeyValuePartialInformation, &key_info, sizeof(KEY_VALUE_PARTIAL_INFORMATION), &ac_lenth); if ( !NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL && status != STATUS_BUFFER_OVERFLOW) { //处理失败 } //如果没有失败,则分配存储空间不足,再次获取 ac_key_info = (PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePoolWithTag(NonPagedPool,ac_lenth,MEM_TAG); if ( ac_key_info == NULL ) { status = STATUS_INSUFFICIENT_RESOURCES; //错误处理 } status = ZwQueryValueKey( my_key, &my_key_name, KeyValuePartialInformation, ac_key_info, ac_lenth, &ac_lenth); if ( !NT_SUCCESS(status) ) { //处理失败 } //成功读取数据到ac_key_info->data中