zoukankan      html  css  js  c++  java
  • 内核模式下的注册表操作

    注册表操作

     
     

    注册表里的几个概念:

    Windows内核函数(2) - 内核模式下的注册表操作 - Fly - 从C开始

     

    1.       创建关闭注册表项

    NTSTATUS 
      ZwCreateKey(
        OUT PHANDLE
      KeyHandle,
        IN ACCESS_MASK  DesiredAccess//访问权限,一般为KEY_ALL_ACCLESS
        IN POBJECT_ATTRIBUTES  ObjectAttributes,
        IN ULONG  TitleIndex//一般为NULL
        IN PUNICODE_STRING  Class  OPTIONAL, //一般为NULL
        IN ULONG  CreateOptions//一般为REG_OPTION_NON_VOLATILE
        OUT PULONG  Disposition  OPTIONAL //返回是打开成功还是创建成功
        );

    如果ZwCreateKey指定的项目不存在,则直接创建这个项目,并利用Disposition 参数返回REG_CREATED_NEW_KEY。如果该项目已经存在,Disposition 参数返回REG_OPENED_EXISTING_KEY。

     

    示例代码:

    //新建注册表项为HKEY_LOCAL_MACHINESOFTWAREMzf

    #define  MY_REG_SOFTWARE_KEY_NAME  L"\Registry\Machine\Software\Mzf"

    #pragma INITCODE

    VOID TetsKey()

    {

             UNICODE_STRING string1;

             RtlInitUnicodeString(&string1, MY_REG_SOFTWARE_KEY_NAME);

            

             OBJECT_ATTRIBUTES  objAttribute;

             InitializeObjectAttributes(&objAttribute, &string1, OBJ_CASE_INSENSITIVE, NULL, NULL);

     

             HANDLE hKey;

             ULONG Des;

             NTSTATUS status = ZwCreateKey(&hKey, KEY_ALL_ACCESS, &objAttribute,

    NULL, NULL, REG_OPTION_NON_VOLATILE, &Des);

     

             if (NT_SUCCESS(status))

             {

                       if (Des == REG_CREATED_NEW_KEY)

                       {

                                KdPrint(("新建注册表项! "));

                       }

                       else

                       {

                                KdPrint(("要创建的注册表项已经存在! "));

                       }

             }

            

    //打开或创建注册表子项

             UNICODE_STRING string2;

             RtlInitUnicodeString(&string2, L"SubKey");

     

             OBJECT_ATTRIBUTES  subObjAttribute;      

             //注意最后第二个参数,为父键的句柄

             InitializeObjectAttributes( &subObjAttribute, &string2, OBJ_CASE_INSENSITIVE, hKey, NULL);

     

             HANDLE hSubKey;

             ULONG subDes;

             status = ZwCreateKey(&hSubKey, KEY_ALL_ACCESS, &subObjAttribute,

    NULL, NULL, REG_OPTION_NON_VOLATILE, &subDes);

     

             if (NT_SUCCESS(status))

             {

                       if (subDes == REG_CREATED_NEW_KEY)

                       {

                                KdPrint(("新建注册表子项! "));

                       }

                       else

                       {

                                KdPrint(("要创建的注册表子项已经存在! "));

                       }

             }

             //关闭注册表句柄

             ZwClose(hKey);

             ZwClose(hSubKey);

    }

     

     

    2.       打开注册表项

    NTSTATUS 
      ZwOpenKey(
        OUT PHANDLE
      KeyHandle,
        IN ACCESS_MASK  DesiredAccess,
        IN POBJECT_ATTRIBUTES  ObjectAttributes
        );

     

     

    3.  添加,修改注册表键值

    注册表键值是以二元形式存储的,既“键名”和“键值”。通过键名设置键值,而键值可以分为以下几类:

    分类 描述
    REG_BINARY 键使用二进制存储
    REG_SZ 键使用宽字符串,字符串以结尾
    REG_EXPAND_SZ 该字符是扩展的字符,其它同上
    REG_MULTI_SZ 键值存储多个字符串,每个字符串以隔开
    REG_DWORD 键值用4字节整型存储
    REG_QWORD 键值使用8字节存储

    在添加和修改注册表键值的时候,要分类进行添加和修改。DDK提供了ZwSetValueKey函数来完成这个任务。

    NTSTATUS 
      ZwSetValueKey(
        IN HANDLE
      KeyHandle,
        IN PUNICODE_STRING  ValueName//要新建或者修改的键名
        IN ULONG  TitleIndex  OPTIONAL, //一般设为0
        IN ULONG  Type,  //键值类型,上表中的一个
        IN PVOID  Data//数据
        IN ULONG  DataSize //记录键值数据大小
        );

    在使用ZwSetValueKey函数的时候,如果指定的键名不存在,则直接创建。否则,对已有的键值进行修改。

     

    示例代码:

    #define  MY_REG_SOFTWARE_KEY_NAME  L"\Registry\Machine\Software\Mzf"

    #pragma INITCODE

    NTSTATUS TetsKey()

    {

             //初始化注册表项

             UNICODE_STRING stringKey;

             RtlInitUnicodeString(&stringKey, MY_REG_SOFTWARE_KEY_NAME);

            

             //初始化OBJECT_ATTRIBUTES结构

             OBJECT_ATTRIBUTES  ObjectAttributes;

             InitializeObjectAttributes(&ObjectAttributes, &stringKey,

    OBJ_CASE_INSENSITIVE, NULL, NULL);

     

             //打开注册表项

             HANDLE hKey;

             NTSTATUS status = ZwOpenKey(&hKey, GENERIC_ALL, &ObjectAttributes);

             if (!NT_SUCCESS(status))

             {

                       KdPrint(("打开注册表项失败! "));

                       return status;

             }

            

             //初始化valueName

             UNICODE_STRING valueName;

             RtlInitUnicodeString(&valueName, L"valueName REG_DWORD");

            

             //设置REG_DWORD键值

             ULONG ulValue = 100;

             status = ZwSetValueKey(hKey, &valueName, 0, REG_DWORD, &ulValue, sizeof(ulValue));

             if (!NT_SUCCESS(status))

             {

                       KdPrint(("设置1键值失败! "));

                       return status;

             }

     

             //设置REG_SZ键值

             RtlInitUnicodeString(&valueName, L"valueName REG_SZ");

     

             WCHAR* str = L"Hello World";

             status = ZwSetValueKey(hKey, &valueName, 0, REG_SZ, str, wcslen(str)*2 + 2);

             if (!NT_SUCCESS(status))

             {

                       KdPrint(("设置2键值失败! "));

                       return status;

             }

     

             //设置REG_BINARY键值

             RtlInitUnicodeString(&valueName, L"valueName REG_BINARY");

     

             UCHAR buffer[10];

             RtlFillMemory(buffer, sizeof(buffer), 0xFF);

             status = ZwSetValueKey(hKey, &valueName, 0, REG_BINARY, buffer, sizeof(buffer));

             if (!NT_SUCCESS(status))

             {

                       KdPrint(("设置3键值失败! "));

                       return status;

             }

     

             //关闭注册表句柄

             ZwClose(hKey);

             return status;

    }

     

     

    4.       查询注册表

    NTSTATUS 
      ZwQueryValueKey(
        IN HANDLE
      KeyHandle,
        IN PUNICODE_STRING  ValueName//要查询的键名
        IN KEY_VALUE_INFORMATION_CLASS  KeyValueInformationClass//查询的类别
        OUT PVOID  KeyValueInformation//返回查询的信息
        IN ULONG  Length//要查数据的长度
        OUT PULONG  ResultLength //实际查询数据的长度
        );

    在使用上述函数对注册表键值进行查询时,需要指定KeyValueInformationClass 的值,这个值可以是KeyValueBasicInformation ,KeyValueFullInformationKeyValuePartialInformation 。

    一般情况下,选择KeyValuePartialInformation就可以查询键值的数据了。它对应查询所返回的结果存放在一个KEY_VALUE_PARTIAL_INFORMATION结构体中。

    typedef struct _KEY_VALUE_PARTIAL_INFORMATION {
      ULONG  TitleIndex;
      ULONG  Type;           //数据的类型
      ULONG  DataLength;     //数据的长度
      UCHAR  Data[1];        //数据指针,这里是变长的数据
    } KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION;

     

    KEY_VALUE_PARTIAL_INFORMATION结构体的长度不固定,所以首先需要确定这个长度。一般使用ZwQueryValueKey分为以下四个步骤:

    (1)     用ZwQueryValueKey获取这个数据结构的长度。

    (2)分配如此长度的内存,用来查询

    (3)再次调用ZwQueryValueKey,获取键值

    (4)回收内存。

     

    示例代码:

    #define MY_REG_SOFTWARE_KEY_NAME  L"\Registry\Machine\Software\Mzf"

    #pragma INITCODE

    NTSTATUS TetsKey()

    {

           //初始化注册表项

           UNICODE_STRING stringKey;

           RtlInitUnicodeString(&stringKey, MY_REG_SOFTWARE_KEY_NAME);

          

           //初始化OBJECT_ATTRIBUTES结构

           OBJECT_ATTRIBUTES  ObjectAttributes;

           InitializeObjectAttributes(&ObjectAttributes, &stringKey,

                  OBJ_CASE_INSENSITIVE, NULL, NULL);

     

           //打开注册表项

           HANDLE hKey;

           NTSTATUS status = ZwOpenKey(&hKey, GENERIC_ALL, &ObjectAttributes);

           if (!NT_SUCCESS(status))

           {

                  KdPrint(("打开注册表项失败! "));

                  return status;

           }

          

           //初始化valueName

           UNICODE_STRING valueName;

           RtlInitUnicodeString(&valueName, L"valueName REG_DWORD");

          

           //获取实际查询的数据的大小

           ULONG ulSize = 0;

           status = ZwQueryValueKey(hKey, &valueName,

                  KeyValuePartialInformation, NULL, 0, &ulSize);

     

           if (status == STATUS_OBJECT_NAME_NOT_FOUND || ulSize == 0)

           {

                  ZwClose(hKey);

                  KdPrint(("注册表键值不存在! "));

                  return status;

           }

          

           //分配实际查询所需的内存空间

           PKEY_VALUE_PARTIAL_INFORMATION pkvpi =

                  (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool(PagedPool, ulSize);

     

           //查询键值

           status = ZwQueryValueKey(hKey, &valueName, KeyValuePartialInformation,

                  pkvpi, ulSize, &ulSize);

          

           if(!NT_SUCCESS(status))

           {

                  ZwClose(hKey);

                  KdPrint(("查询注册表键值失败! "));

                  return status;

           }

           //判断是否为REG_DWORD类型

           if (pkvpi->Type == REG_DWORD && pkvpi->DataLength == sizeof(ULONG))

           {

                  PULONG a = (PULONG)pkvpi->Data;

                  KdPrint(("%d ", *a));

           }

     

           //关闭注册表句柄

           ZwClose(hKey);

           return status;

    }

     

     

    5.       枚举子项

    DDK提供了两个函数,他们组合使用可以起到枚举子项的作用。

    NTSTATUS 
      ZwQueryKey(
        IN HANDLE
      KeyHandle,
        IN KEY_INFORMATION_CLASS  KeyInformationClass,
        OUT PVOID  KeyInformation,
        IN ULONG  Length,
        OUT PULONG  ResultLength
        );

     

    NTSTATUS 
      ZwEnumerateKey(
        IN HANDLE
      KeyHandle,
        IN ULONG  Index,
        IN KEY_INFORMATION_CLASS  KeyInformationClass,
        OUT PVOID  KeyInformation,
        IN ULONG  Length,
        OUT PULONG  ResultLength
        );

     

    ZwQueryKey的作用主要是获得注册表项究竟有多少个子项,而ZwEnumerateKey的作用主要是针对第几个子项,获取该子项的具体信息。

    在使用ZwQueryKey时,可以将参数KeyInformationClass指定为KeyFullInformation。这样参数KeyInformation就对应一个KEY_FULL_INFORMATION的数据结构。该结构中的SubKeys指明了项中有多少子项。

             在使用ZwEnumerateKey时,需要将参数KeyInformationClass指定为KeyBasicInformation,已返回子项的基本信息。

             注意:上面提到的这两个结构都是变长的,在使用时需要调用两次函数。第一次获得长度,第二次真正得到数据。

     

    示例代码:

    #define  MY_REG_SOFTWARE_KEY_NAME  L"\Registry\Machine\Software\Mzf"

    #pragma INITCODE

    NTSTATUS TetsKey()

    {

             //初始化注册表项

             UNICODE_STRING stringKey;

             RtlInitUnicodeString(&stringKey, MY_REG_SOFTWARE_KEY_NAME);

            

             //初始化OBJECT_ATTRIBUTES结构

             OBJECT_ATTRIBUTES  ObjectAttributes;

             InitializeObjectAttributes(&ObjectAttributes, &stringKey,

                       OBJ_CASE_INSENSITIVE, NULL, NULL);

     

             //打开注册表项

             HANDLE hKey;

             NTSTATUS status = ZwOpenKey(&hKey, GENERIC_ALL, &ObjectAttributes);

             if (!NT_SUCCESS(status))

             {

                       KdPrint(("打开注册表项失败! "));

                       return status;

             }

     

             //第一次调用ZwQueryKey,为了获取KEY_FULL_INFORMATION数据的长度

             ULONG ulSize = 0;

             status = ZwQueryKey(hKey, KeyFullInformation, NULL, 0, &ulSize);

             //申请内存

             PKEY_FULL_INFORMATION pkfi =

    (PKEY_FULL_INFORMATION)ExAllocatePool(PagedPool, ulSize);

            

             //第二次调用ZwQueryKey,为了获取KEY_FULL_INFORMATION数据

             status = ZwQueryKey(hKey, KeyFullInformation, pkfi, ulSize, &ulSize);

            

             for (ULONG i=0; i<pkfi->SubKeys; i++)

             {

                       //第一次调用ZwEnumerateKey,为了获取KEY_BASIC_INFORMATION数据的长度

                       ZwEnumerateKey(hKey, i, KeyBasicInformation, NULL, 0, &ulSize);

                       //非配内存

                       PKEY_BASIC_INFORMATION pkbi =

                                                   (PKEY_BASIC_INFORMATION)ExAllocatePool(PagedPool, ulSize);

                       //第二次调用ZwEnumerateKey,为了获取KEY_BASIC_INFORMATION数据                              ZwEnumerateKey(hKey, i, KeyBasicInformation, pkbi, ulSize, &ulSize);

                      

                       UNICODE_STRING string;

                       string.Length = string.MaximumLength = (USHORT)pkbi->NameLength;

                       string.Buffer = (PWSTR)ExAllocatePool(PagedPool, string.Length);

                       RtlCopyMemory(string.Buffer, pkbi->Name, string.Length);

                       KdPrint(("第 %d 个子项: %wZ! ", i, &string));

                       //回收内存

                       ExFreePool(pkbi);

                       RtlFreeUnicodeString(&string);

             }

    //回收内存

             ExFreePool(pkfi);

             //关闭注册表句柄

             ZwClose(hKey);

             return status;

    }

     

     

    6.       枚举子键

    枚举子键是通过ZwQueryKey和ZwEnumerateValueKey两个函数配合完成的。

    NTSTATUS
      ZwEnumerateValueKey(
        IN HANDLE
      KeyHandle,
        IN ULONG  Index,
        IN KEY_VALUE_INFORMATION_CLASS  KeyValueInformationClass,
        OUT PVOID  KeyValueInformation,
        IN ULONG  Length,
        OUT PULONG  ResultLength
        );

     

    示例代码:

    #define  MY_REG_SOFTWARE_KEY_NAME  L"\Registry\Machine\Software\Mzf"

    #pragma INITCODE

    NTSTATUS TetsKey()

    {

             //初始化注册表项

             UNICODE_STRING stringKey;

             RtlInitUnicodeString(&stringKey, MY_REG_SOFTWARE_KEY_NAME);

            

             //初始化OBJECT_ATTRIBUTES结构

             OBJECT_ATTRIBUTES  ObjectAttributes;

             InitializeObjectAttributes(&ObjectAttributes, &stringKey,

                       OBJ_CASE_INSENSITIVE, NULL, NULL);

     

             //打开注册表项

             HANDLE hKey;

             NTSTATUS status = ZwOpenKey(&hKey, GENERIC_ALL, &ObjectAttributes);

             if (!NT_SUCCESS(status))

             {

                       KdPrint(("打开注册表项失败! "));

                       return status;

             }

     

             ULONG ulSize = 0;

             //查询注册表

             status = ZwQueryKey(hKey, KeyFullInformation, NULL, 0, &ulSize);

     

             PKEY_FULL_INFORMATION pkfi =

    (PKEY_FULL_INFORMATION)ExAllocatePool(PagedPool, ulSize);

             //查询注册表

             status = ZwQueryKey(hKey, KeyFullInformation, pkfi, ulSize, &ulSize);

            

             for (ULONG i=0; i<pkfi->Values; i++)

             {

                       //枚举注册表

                       ZwEnumerateValueKey(hKey, i, KeyValueBasicInformation, NULL, 0, &ulSize);

                       PKEY_VALUE_BASIC_INFORMATION pkbi =

                                         (PKEY_VALUE_BASIC_INFORMATION)ExAllocatePool(PagedPool, ulSize);

                       ZwEnumerateValueKey(hKey, i, KeyValueBasicInformation, pkbi, ulSize, &ulSize);

                      

                       UNICODE_STRING string;

                       string.Length = string.MaximumLength = (USHORT)pkbi->NameLength;

                       string.Buffer = (PWSTR)ExAllocatePool(PagedPool, string.Length);

                       RtlCopyMemory(string.Buffer, pkbi->Name, string.Length);

                       KdPrint(("第 %d 个子项: %wZ! ", i, &string));

                       //判断键值类型

                       if (pkbi->Type == REG_SZ)

                       {

                                KdPrint(("REG_SZ "));

                       }

                       ExFreePool(pkbi);

                       RtlFreeUnicodeString(&string);

             }

             ExFreePool(pkfi);

             //关闭注册表句柄

             ZwClose(hKey);

             return status;

    }

     

    7.       删除子项

    NTSTATUS 
      ZwDeleteKey(
        IN HANDLE
      KeyHandle
        );

    需要指出,该函数只能删除没有子项的项目。如果项中有子项,则不能删除。这时候需要先将该项中的所有子项全部删除,再删除该项。

     

    8.  其他

    为了简化注册表的操作,DDK还提供了一系列以Rtl开头的运行时函数,这些函数把前面介绍的函数进行了封装。往往一条函数就能实现前面介绍的若干条函数的功能。

    分类 描述
    RtlCreateRegistryKey 创建注册表
    RtlCheckRegistryKey 查看某注册表项是否存在
    RtlWriteRegistryValue 写注册表
    RtlDeleteRegistryValue 删除注册表的子键
  • 相关阅读:
    Commons JXPath
    10到十分精彩的智力题,你能过关几道?
    程序员下班电脑不关机的5大原因,你中招了吗?
    程序员下班电脑不关机的5大原因,你中招了吗?
    MySQL的一些概念笔记
    MySQL的一些概念笔记
    Shell中I/O重定向的用法笔记
    Shell中I/O重定向的用法笔记
    Shell重定向的概念笔记
    Shell重定向的概念笔记
  • 原文地址:https://www.cnblogs.com/ansen312/p/5865289.html
Copyright © 2011-2022 走看看