Winpcap分析 -- getAdaptersList

来源:互联网 发布:java开发面试宝典 编辑:程序博客网 时间:2024/06/06 08:45

getAdaptersList:这个函数主要的逻辑是读取注册表的数据

  • 打开SYSTEM//CurrentControlSet//Control//Class//{4D36E972-E325-11CE-BFC1-08002BE10318}键项
    •  
      • InitializeObjectAttributes(&objAttrs, &AdapterListKey,
                OBJ_CASE_INSENSITIVE, NULL, NULL);
            status = ZwOpenKey(&keyHandle, KEY_READ, &objAttrs);
    • 说明:InitializeObjectAttributes和ZwOpenKey的wdk描述,请参考:
      • http://blog.csdn.net/huang_shao_bin/archive/2010/02/06/5294008.aspx
      • http://blog.csdn.net/huang_shao_bin/archive/2010/02/06/5294014.aspx
    • 参数:
      1. objAttrs:需要初始化的一个对象,主要为了调用ZwOpenKey提供数据
      2. AdapterListKey:注册表键项值,需要打开的注册表的键项值,也即上面出现的字符串
      3. 对大小写不敏感所以需要指定OBJ_CASE_INSENSITIVE标志
      4. 后面的参数主要是用于路径对象的跟目录和安全描述符,这里不需要
    • 相关数据:
      •  objAttrs
  • 根据打开的键值句柄,遍历所有子项,再获取每个子项下的Linkage子项,在Linkage子项中查找Export键值的值

    regedit

    •  
      • 遍历所有子项
        •  
          • while((status=ZwEnumerateKey(keyHandle,i,KeyBasicInformation,AdapInfo,sizeof(AdapInfo),&resultLength))==STATUS_SUCCESS)
        • 说明:ZwEnumerateKey的wdk描述,请参考:
          • http://blog.csdn.net/huang_shao_bin/archive/2010/02/06/5294018.aspx
        • 参数:
          • keyHandle:ZwOpenKey返回的句柄
          • i:需要获得的子键的索引,从0开始不断的计数,直到找不到为止
          • KeyBasicInformation:是一个枚举类型KEY_INFORMATION_CLASS,说明需要获取哪些信息,这里只获得基本信息就可以
          • AdapInfo:根据KEY_INFORMATION_CLASS类型定义不用的数据结构来接收函数返回的信息
          • sizeof(AdapInfo):接收数据的buffer的大小
          • resultLength:返回接收buffer需要的长度或者实际返回数据内容的长度,具体请参考wdk文档
          • 相关数据:
          •  AdapInfo
      • 打开Linkage子项
        •  

            RtlCopyMemory(ExportKeyName,
                            ExportKeyPrefix,
                            ExportKeyPrefixSize);
            RtlCopyMemory((PCHAR)ExportKeyName+ExportKeyPrefixSize,
                            tInfo->Name,
                            tInfo->NameLength+2);
            RtlCopyMemory((PCHAR)ExportKeyName+ExportKeyPrefixSize+tInfo->NameLength,
                            LinkageKeyPrefix,
                            LinkageKeyPrefixSize);
            RtlInitUnicodeString(&AdapterKeyName, ExportKeyName);
            InitializeObjectAttributes(&objAttrs, &AdapterKeyName,
                            OBJ_CASE_INSENSITIVE, NULL, NULL);
            status=ZwOpenKey(&ExportKeyHandle,KEY_READ,&objAttrs);

      • 查询Export键值的信息
        •  
          • status = ZwQueryValueKey(ExportKeyHandle, &FinalExportKey,
                            KeyValuePartialInformation, &valueInfo,
                            sizeof(valueInfo), &resultLength);
        • 说明:ZwQueryValueKey的wdk描述,请参考:
          • http://blog.csdn.net/huang_shao_bin/archive/2010/02/06/5294020.aspx
        • 参数:基本参数和ZwEnumerateKey类似,详细请参考wdk文档
      • 计算数据大小,并重新分配内存进行查询
        •  

            ULONG valueInfoLength = valueInfo.DataLength + FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
                                PKEY_VALUE_PARTIAL_INFORMATION valueInfoP =    (PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePoolWithTag(PagedPool, valueInfoLength, '1PWA');
                                if (valueInfoP != NULL) {
                                    status = ZwQueryValueKey(ExportKeyHandle, &FinalExportKey,
                                        KeyValuePartialInformation,
                                        valueInfoP,
                                        valueInfoLength, &resultLength);

        • 说明:
          • valueInfo.DataLength :Export键值的数据长度
          • FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]):获得Data[0]成员在KEY_VALUE_PARTIAL_INFORMATION结构中的偏移
          • 上述两项加起来就是总长度,然后重新查询Export键值信息,就可以通过valueInfoP->Data获得键值的数据
  • 对上述的操作进行循环,就可以获得所有数据,下面来看看循环中的一些内存分配和长度计算
    •  

        if( BufPos + valueInfoP->DataLength > BufLen ) {
                                        // double the buffer size
                                        PWCHAR DeviceNames2 = (PWCHAR) ExAllocatePoolWithTag(PagedPool, BufLen
                                            << 1, '0PWA');
                                        if( DeviceNames2 ) {
                                            RtlCopyMemory((PCHAR)DeviceNames2, (PCHAR)DeviceNames, BufLen);
                                            BufLen <<= 1;
                                            ExFreePool(DeviceNames);
                                            DeviceNames = DeviceNames2;
                                        }
                                    }

        if( BufPos + valueInfoP->DataLength < BufLen ) {
                                        RtlCopyMemory((PCHAR)DeviceNames+BufPos,
                                            valueInfoP->Data,
                                            valueInfoP->DataLength);
                                        BufPos+=valueInfoP->DataLength-2;
                                    }

        // terminate the buffer
                        DeviceNames[BufPos/2]=0;
                        DeviceNames[BufPos/2+1]=0;

    • BufLen 是UINT型数据,初始值是4096
      • 当buffer用完的时候,是通过移位来增加buffer长度,并重新分配一块新的内存区域
      • 通过拷贝内存把原来数据拷贝到新的内存区域中
      • 释放原来的内存区域
      • 重新给指针赋值,指向新的内存区域
      • 关于BufPos+=valueInfoP->DataLength-2,本人不知道原因,但是通过windbg查看,valueInfoP->DataLength-2的长度刚好就是最后一个字符的长度再往后2个字符,刚好配合后面的置0操作。也就是说valueInfoP->DataLength是数据的实际长度再加上4个字节的。
      • Memory
原创粉丝点击