深度剖析WinPcap之(三)——所涉及的Windows驱动基础知识(4)

本文转自http://eslxf.blog.51cto.com/918801/196917

 

v/:* {behavior:url(#default#VML);} o/:* {behavior:url(#default#VML);} w/:* {behavior:url(#default#VML);} .shape {behavior:url(#default#VML);}

1.1.8 内核的注册表操作

在驱动程序的开发中,经常会对注册表进行操作。 DDK 提供一套对注册表操作的函数。
v/:* {behavior:url(#default#VML);} o/:* {behavior:url(#default#VML);} w/:* {behavior:url(#default#VML);} .shape {behavior:url(#default#VML);} v/:* {behavior:url(#default#VML);} o/:* {behavior:url(#default#VML);} w/:* {behavior:url(#default#VML);} .shape {behavior:url(#default#VML);}
3-1 注册表的在组成
首先对注册表的五个主要组成部分说明一下,如图 3-1 所示。
注册表项:注册表中的一个项目,类似目录的概念。每个项中存储多个二元结构,键名一键值。每个项中,可以有若干个子项。
注册表子项:类似于目录中的子目录。
键名:通过键名可以寻找到相应的键值。
键值类别:每个键值存储的时候有不同的类别,可以是整型、字符串等数据。
键值:键名下对应存储的数据。
1.1.8.1     初始化一个 OBJECT_ATTRIBUTES 结构体
为了能对注册执行操作,必须首先调用 InitializeObjectAttributes 函数初始化一个 OBJECT_ATTRIBUTES 结构体,函数原形如下:
VOID
InitializeObjectAttributes(
OUT POBJECT_ATTRIBUTES  InitializedAttributes,
        IN PUNICODE_STRING  ObjectName,
        IN ULONG  Attributes,
        IN HANDLE  RootDirectory,
        IN PSECURITY_DESCRIPTOR  SecurityDescriptor
    );
参数 InitializedAttributes   指向需要初始化的 OBJECT_ATTRIBUTES 结构体。参数 ObjectName   描述需要打开注册表对象的名称,用 Unicode 字符串表示。参数 Attributes 为标识,如设置为 OBJ_CASE_INSENSITIVE ,那么把  ObjectName 与已存在的对象进行比较时就不区分大小写。参数 RootDirectory   描述 ObjectName 参数的根目录,如果 ObjectName 是一个完全的名称,则设为 NULL 。 参数 SecurityDescriptor 为一个安全描述,驱动程序可设为 NULL ,采用默认的安全。
 
1.1.8.2      打开注册表
  DDK 提供了内核函数 ZwOpenKey 打开一个已存在的注册表项。如果 ZwOpenKey 指定的项不存在,就不会创建这个项,而是返回一个错误状态。该函数的声明如下:
NTSTATUS
ZwOpenKey(
           OUT PHANDLE  KeyHandle,
           IN ACCESS_MASK  DesiredAccess,
           IN POBJECT_ATTRIBUTES  ObjectAttributes
    );
参数 KeyHandle 为返回被打开的句柄。参数 DesiredAccess 为打开的权限,一般设为 KEY_ALL_ACCESS 。参数 ObjectAttri110utesOBJECT_ATTRIBUTES 数据结构,指示打开的状态。
   如果打开成功函数ZwOpenKey返回STATUS_SUCCESS,否则返回一个错误代码,可能为STATUS_INVALID_HANDLE或STATUS_ACCESS_DENIED。
 
1.1.8.3     关闭注册表
打开的注册表,如果不在使用需要采用 ZwClose函数 关闭它,函数原型如下。
NTSTATUS
 ZwClose(
IN HANDLE  Handle
);
参数 Handle 为所要关闭的注册表句柄。
 
1.1.8.4   查询注册表
     驱动程序中有时需要对注册表的项进行查询,从而获取注册表的键值 aDDK 提供的 ZwQueryValueKey 函数可以完成这个任务,其声明如下:
NTSTATUS
ZwQueryValueKey(
           IN HANDLE  KeyHandle,
           IN PUNICODE_STRING  ValueName,
           IN KEY_VALUE_INFORMATION_CLASS  KeyValueInformationClass,
           OUT PVOID  KeyValueInformation,
           IN ULONG  Length,
           OUT PULONG  ResultLength
);
参数 KeyHandle 为打开的注册表句柄。参数 ValueName 为要查询的键名。参数 KeyValuelnformationClass 决定不同的查询类别。参数 KeyValuelnformation 选择一种查询类别。选择 KeyValueBasiclnformationKeyValueFulllnformation 或者 KeyValuePartiallnformation 。参数 Length 为要查数据的长度。参数 ResultLength 为实际查询返回的数据长度。
     如果打开成功函数返回 STATUS_SUCCESS ,否则返回一个错误代码。
使用 ZwQueryValueKey 函数查询注册表单时,需要用 KeyValuelnformationClass 选择一种查询方式。这可以是 KeyVajueBasiclnformationKeyValueFulllnformation 或者 KeyValuePartiallnformation 中的一种。这分别代表查询基本信息,查询全部信息和查询部分信息,每种查询类型会有对应的一种数据结构获得查询结果。
一般情况下,选择 KeyValuePartiallnformation 就可以查询键值的数据了,它对应的查询数据结构是 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 分为 4 个步骤操作。
<!--[if !supportLists]--> Ø         <!--[endif]--> 用 ZwQueryValueKey 获取这个数据结构的长度。
<!--[if !supportLists]--> Ø         <!--[endif]--> 分配如此长度的内存,用来查询。
<!--[if !supportLists]--> Ø         <!--[endif]--> 再次调用 ZwQueryValueKey ,获取键值。
<!--[if !supportLists]--> Ø         <!--[endif]--> 回收内存。
如果选择 KeyValueFulllnformation,它对应的查询数据结构是 KEY_VALUE_FULL_INFORMATION的数据结构。
typedef struct _KEY_VALUE_FULL_INFORMATION {
ULONG  TitleIndex;
ULONG  Type;
ULONG  DataOffset;
ULONG  DataLength;
ULONG  NameLength;
WCHAR  Name[1];   //变量的大小
} KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION;
 
1.1.8.5    枚举子项
     在注册表的操作中,还经常有另外两种操作,分别是枚举子项和枚举子键。枚举子项就是事先不知道该项中有多少个子项目,用某个函数将子项一一列举出来。而枚举子键是事先不知道该项中有多少个子键,用某个函数一一将子键列举出来。
DDK 提供了列举子项的 ZwQueryKey 函数和 ZwEnumerateKey 。先看一下这两个函数的声明。
NTSTATUS
ZwQueryKey(
    IN HANDLE  KeyHandle,
    IN KEY_INFORMATION_CLASS  KeyInformationClass,
    OUT PVOID  KeyInformation,
    IN ULONG  Length,
    OUT PULONG  ResultLength
);
参数 KeyHandle 为注册表项的句柄。参数 KeylnformationClass 为查询的类别,一般选择 KeyFulllnformation 。参数 Keylnformation 为查询的数据指针。如果 KeylnformationClassKeyFulllnformation ,则该指针指向一个 KEY_FULL_INFORMATION 的数据结构。参数  Length 为数据长度。参数 ResultLength 为实际返回数据的长度。
如果函数成功则返回 STATUS_SUCCESS ,否则返回一个错误代码。
NTSTATUS
ZwEnumerateKey(
IN HANDLE  KeyHandle,
             IN ULONG  Index,
           IN KEY_INFORMATION_CLASS  KeyInformationClass,
           OUT PVOID  KeyInformation,
           IN ULONG  Length,
           OUT PULONG  ResultLength
    );
参数 KeyHandle 为注册表项句柄。参数 Index: 为由 0 开始的索引。参数 KeylnformationClass 为子项的信息类型。参数 Length 为子项信息的长度。参数 ResultLength 为返回子键信息的长度。
如果函数成功则返回 STATUS_SUCCESS ,否则返回一个错误代码。
    ZwQueryKey 的作用主要是获得某注册表项究竟有多少个子项,而 ZwEnumerateKey 的作用主要是针对第几个子项获取该子项的具体信息。
     在使用 ZwQueryKey 时,可以将参数 KeylnformationClass 指定为 KeyFulllnformation 。这样参数 Keylnformation 就对应一个 KEY_FULL_INFORMATION 的数据结构,该数据结构中的 SubKeys 指明了项中有多少个子项。
   KEY_FULL_INFORMATION 数据结构的大小是变长的,所以要调用两次
ZwQueryKey 。第一次获取 KEY_FULL_INFORMATION 数据的长度,第二次真正获取 KEY_FULL_INFORMATION 数据。
     在使用 ZwEnumerateKey 时,需要将参数 KeylnformationClass 设置为 KeyBasicInformation ,这样其参数 Keylnformation 兢能对应 KEY_B ASIC_INFORMATION 的数据结构。
同理 KEY_BASIC_INFORMATION 也是变长的数据结构,需要两次调用 ZwEnumerateKey 。第一次获取 KEY_BASIC_INFORMATION 的长度,第二次获取 KEY_BASIC_INFORMATION 数据。
   
1.1.8.6     枚举子键
     和枚举子项类似,枚举子键是通过 ZwQueryKeyZwEnumerateValueKey 两个函数的配合完成的。 ZwEnumerateValueKey 函数的使用和 ZwEnumerateKey 函数的使用类似。
NTSTATUS
ZwEnumerateValueKey(
IN HANDLE  KeyHandle,
        IN ULONG  Index,
        IN KEY_VALUE_INFORMATION_CLASS  KeyValueInformationClass,
        OUT PVOID  KeyValueInformation,
        IN ULONG  Length,
        OUT PULONG  ResultLength
    );
 
1.1.8.7    WinPcap中注册表操作实例
下列代码是 WinPcap 中对注册操作的实际代码。
PWCHAR getAdaptersList(void)
{
    …
  /*
*设置一个OBJECT_ATTRIBUTES类型的参数objAttrs,为了后续调用
*其中NDIS_STRING AdapterListKey =
*  NDIS_STRING_CONST("//Registry//Machine//System//CurrentControlSet
*      //Control//Class//{4D36E972-E325-11CE-BFC1-08002BE10318}");
*/
    InitializeObjectAttributes(&objAttrs, &AdapterListKey,
        OBJ_CASE_INSENSITIVE, NULL, NULL);
 
/*打开注册表表项,返回objAttrs中所描述的注册表表项的句柄*/
    status = ZwOpenKey(&keyHandle, KEY_READ, &objAttrs);
    if (!NT_SUCCESS(status)) {
        //打开失败
    }
    else { //打开成功      
        ULONG resultLength;
        KEY_VALUE_PARTIAL_INFORMATION valueInfo;
        CHAR AdapInfo[1024];
        UINT i=0;
        /*遍历设备链表,获取一个已打开注册表项子项的信息*/                      while((status=ZwEnumerateKey(keyHandle,i,KeyBasicInformation,
AdapInfo,sizeof(AdapInfo),&resultLength))==STATUS_SUCCESS)
{
            …     
/*设置一个OBJECT_ATTRIBUTES类型的参数objAttrs,为了后续调用*/
            InitializeObjectAttributes(&objAttrs, &AdapterKeyName,
                    OBJ_CASE_INSENSITIVE, NULL, NULL);     
          /*打开注册表表项,返回objAttrs中所描述的注册表表项的句柄*/
status=ZwOpenKey(&ExportKeyHandle,KEY_READ,&objAttrs);
            /*查找“Export”键名的键值信息*/
            status = ZwQueryValueKey(ExportKeyHandle, &FinalExportKey,
                    KeyValuePartialInformation, &valueInfo,
                    sizeof(valueInfo), &resultLength);
               
if  (!NT_SUCCESS(status) && (status != STATUS_BUFFER_OVERFLOW)) {
                //查询失败
            }
            else { //查询成功
/*计算所需的内存大小*/
/*分配内存,用于查询*/
                if (valueInfoP != NULL) {//分配内存成功
                    status = ZwQueryValueKey(ExportKeyHandle,
                            &FinalExportKey,
                            KeyValuePartialInformation,
                            valueInfoP,
                            valueInfoLength, &resultLength);
                    if (!NT_SUCCESS(status)) {
                        //查询失败
                    }
                    else{//查询成功
                    …
                    }
                    ExFreePool(valueInfoP);
                }
                else {
//分配用于查询的内存失败
                }
            }//一次查找“Export”键名的键值信息结束
            …
            //关闭注册表子项
            ZwClose (ExportKeyHandle);
            i++;
        }//结束while语句
 
/*关闭注册表项*/
        ZwClose (keyHandle);          
    }
}

什么是WinPcap WinPcap是一个基于Win32平台的,用于捕获网络数据包并进行分析的开源库. 大多数网络应用程序通过被广泛使用的操作系统元件来访问网络,比如sockets。 这是一种简单的实现方式,因为操作系统已经妥善处理了底层具体实现细节(比如协议处理,封装数据包等等),并且提供了一个与读写文件类似的,令人熟悉的接口。 然而,有些时候,这种“简单的方式”并不能满足任务的需求,因为有些应用程序需要直接访问网络中的数据包。也就是说,那些应用程序需要访问原始数据包,即没有被操作系统利用网络协议处理过的数据包。 WinPcap产生的目的,就是为Win32应用程序提供这种访问方式; WinPcap提供了以下功能 捕获原始数据包,无论它是发往某台机器的,还是在其他设备(共享媒介)上进行交换的 在数据包发送给某应用程序前,根据用户指定的规则过滤数据包 将原始数据包通过网络发送出去 收集并统计网络流量信息 以上这些功能需要借助安装在Win32内核中的网络设备驱动程序才能实现,再加上几个动态链接库DLL。 所有这些功能都能通过一个强大的编程接口来表现出来,易于开发,并能在不同的操作系统上使用。这本手册的主要目标是在一些程序范例的帮助下,叙述这些编程接口的使用。 如果您现在就想开始摸索这些功能,您可以直接进入 WinPcap用户手册. 哪些程序在使用WinPcap WinPcap可以被用来制作许多类型的网络工具,比如具有分析,解决纷争,安全和监视功能的工具。特别地,一些基于WinPcap的典型应用有: 网络与协议分析器 (network and protocol analyzers) 网络监视器 (network monitors) 网络流量记录器 (traffic loggers) 网络流量发生器 (traffic generators) 用户级网桥及路由 (user-level bridges and routers) 网络入侵检测系统 (network intrusion detection systems (NIDS)) 网络扫描器 (network scanners) 安全工具 (security tools) 什么是WinPcap做不到的 WinPcap能 独立地 通过主机协议发送和接受数据,如同TCP-IP。这就意味着WinPcap不能阻止、过滤或操纵同一机器上的其他应用程序的通讯:它仅仅能简单地"监视"在网络上传输的数据包。所以,它不能提供类似网络流量控制、服务质量调度和个人防火墙之类的支持
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值