深度剖析WinPcap之(六)――驱动程序的初始化与清除(3)

1.3.2        getTcpBindings函数

函数getTcpBindings返回绑定到TCP/IP的MAC。函数原型如下:
PKEY_VALUE_PARTIAL_INFORMATION getTcpBindings(VOID);
如果getAdaptersList函数失败,NPF通过该函数试图获取TCP/IP的绑定。函数通过对注册表项HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Linkage下Bind键值获得TCP-IP绑定的适配器。函数返回指向注册表”Bind”键名的键值的指针,该注册表键值包含绑定了TCP/IP的适配器。
深度剖析WinPcap之(六)――驱动程序的初始化与清除(3)_第1张图片
图5-3 注册表项Tcpip\Linkage
clip_image004
图5-4 Bind键名的键值

函数的主要代码如下:
PKEY_VALUE_PARTIAL_INFORMATION getTcpBindings(void)
{
  PKEY_VALUE_PARTIAL_INFORMATION result = NULL;
  OBJECT_ATTRIBUTES objAttrs;
  NTSTATUS status;
  HANDLE keyHandle;
 
/*
*设置一个OBJECT_ATTRIBUTES类型的参数objAttrs,为了后续调用
*其中NDIS_STRING tcpLinkageKeyName =
* NDIS_STRING_CONST(\\Registry\\Machine\\System
*      L"\\CurrentControlSet\\Services\\Tcpip\\Linkage");
*/
  InitializeObjectAttributes(&objAttrs, &tcpLinkageKeyName,
      OBJ_CASE_INSENSITIVE, NULL, NULL);
   
/*打开注册表表项,返回objAttrs中所描述的注册表表项的句柄*/
  status = ZwOpenKey(&keyHandle, KEY_READ, &objAttrs);
  if (!NT_SUCCESS(status))
  {//打开失败
  }
  else
  {//成功打开
ULONG resultLength;
        KEY_VALUE_PARTIAL_INFORMATION valueInfo;
/*
*对注册表表项进行查询,其中bindValueName的定义为
*NDIS_STRING bindValueName = NDIS_STRING_CONST("Bind");
*/
        status = ZwQueryValueKey(keyHandle, &bindValueName,
                 KeyValuePartialInformation, &valueInfo,
                 sizeof(valueInfo), &resultLength);
      if (!NT_SUCCESS(status) && (status != STATUS_BUFFER_OVERFLOW))
      {//查询失败
      }
      else
      {    /*计算所需的内存大小*/
ULONG valueInfoLength = valueInfo.DataLength +
FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
            /*分配内存,用于查询*/
PKEY_VALUE_PARTIAL_INFORMATION valueInfoP =           (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePoolWithTag(
PagedPool, valueInfoLength, '2PWA');
 
          if (valueInfoP != NULL)
          {  /*对注册表表项进行查询,获取键名为”Bind”的键值信息*/
              status = ZwQueryValueKey(keyHandle, &bindValueName,
                  KeyValuePartialInformation,
                  valueInfoP,
                  valueInfoLength, &resultLength);
 
              if (!NT_SUCCESS(status))
              {//查询失败
                  ExFreePool(valueInfoP);
              }
              else
              {
                  if (valueInfoLength != resultLength)
                  {//失败,查询结果的长度前后不一致
                      ExFreePool(valueInfoP);
                  }
                  else
                  {
                      if (valueInfoP->Type != REG_MULTI_SZ)
                      {//失败,键名”Bind”的键值类型不是REG_MULTI_SZ
                              ExFreePool(valueInfoP);
                      }
                      else
                      { /*所有的操作正确*/
                          result = valueInfoP;
                      }
                  }
              }
          }
      }
/*关闭注册表*/
      ZwClose(keyHandle);
  }
/*返回查询的数据*/
return result;
}
 

1.3.3       NPF_CreateDevice函数

函数NPF_CreateDevice对一个给定的MAC创建一个设备。NPF驱动程序也调用 NPF_CreateDevice 函数,通过IoCreateDevice系统接口把Open/close,read/write与IOCTL请求的句柄地址传递给操作系统。
函数原型如下:
BOOLEAN
NPF_CreateDevice(IN OUT PDRIVER_OBJECT adriverObjectP,
                     IN PUNICODE_STRING amacNameP
)
参数adriverObjectP是用来与设备相关联的驱动对象,例如NPF的一个实例。参数 amacNameP是所创建设备将要指向的网络接口名称。
如果函数成功,返回非0值。
NPF对每一个可用的网络适配器只创建一个设备。该新设备指向该NPF驱动程序,但包含关于原始设备的信息。通过这种方式,当用户打开该新设备时,NPF将能够确定使用正确的适配器。
函数的主要代码如下:
BOOLEAN NPF_CreateDevice(IN OUT PDRIVER_OBJECT adriverObjectP,
                     IN PUNICODE_STRING amacNameP)
{
    NTSTATUS status;
    PDEVICE_OBJECT devObjP;
    UNICODE_STRING deviceName;
    UNICODE_STRING deviceSymLink;
   
/*检查amacNameP->Buffer是否包含合法的 “\\Device\\”子字符串*/
    if (RtlCompareMemory(amacNameP->Buffer, devicePrefix.Buffer,
        devicePrefix.Length) < devicePrefix.Length)
    {
        return FALSE;
    }
/*分配设置设备对象的名称的内存空间*/
    deviceName.Length = 0;
    deviceName.MaximumLength = (USHORT)(amacNameP->Length +
        g_NPF_Prefix.Length + sizeof(UNICODE_NULL));
    deviceName.Buffer = ExAllocatePoolWithTag(PagedPool,
 deviceName.MaximumLength, '3PWA');
    if (deviceName.Buffer == NULL)
        return FALSE;
 
/*分配用户可见的设备名称的内存空间*/
    deviceSymLink.Length = 0;
    deviceSymLink.MaximumLength=
(USHORT)(amacNameP->Length-devicePrefix.Length
        + symbolicLinkPrefix.Length
        + g_NPF_Prefix.Length
        + sizeof(UNICODE_NULL));
    deviceSymLink.Buffer = ExAllocatePoolWithTag(NonPagedPool,
deviceSymLink.MaximumLength, '3PWA');
    if (deviceSymLink.Buffer  == NULL)
    {
        ExFreePool(deviceName.Buffer);
        return FALSE;
    }
 
/*生成设置设备对象的名称*/
    RtlAppendUnicodeStringToString(&deviceName, &devicePrefix);
    RtlAppendUnicodeStringToString(&deviceName, &g_NPF_Prefix);
    RtlAppendUnicodeToString(&deviceName, amacNameP->Buffer +
        devicePrefix.Length / sizeof(WCHAR));
 
/*生成用户可见的设备名称*/
    RtlAppendUnicodeStringToString(&deviceSymLink, &symbolicLinkPrefix);
    RtlAppendUnicodeStringToString(&deviceSymLink, &g_NPF_Prefix);
    RtlAppendUnicodeToString(&deviceSymLink, amacNameP->Buffer +
        devicePrefix.Length / sizeof(WCHAR));
       
/*为驱动程序的使用者分配内存,并初始化一个设备对象*/
    status = IoCreateDevice(adriverObjectP,
        sizeof(DEVICE_EXTENSION),
        &deviceName,
        FILE_DEVICE_TRANSPORT,
        FILE_DEVICE_SECURE_OPEN,   
        FALSE,
        &devObjP);
 
    if (NT_SUCCESS(status))
    {
PDEVICE_EXTENSION devExtP =
(PDEVICE_EXTENSION)devObjP->DeviceExtension;
        devObjP->Flags |= DO_DIRECT_IO;
//设置适配器的名称
        RtlInitUnicodeString(&devExtP->AdapterName,amacNameP->Buffer);
       
       /*在一个设备对象名称与一个用户可见的名称之间建立一个符号连接*/
        if (IoCreateSymbolicLink(&deviceSymLink,&deviceName) !=
STATUS_SUCCESS)
        {//创建连接失败,函数返回
            ExFreePool(deviceName.Buffer);
            ExFreePool(deviceSymLink.Buffer);
            devExtP->ExportString = NULL;
            return FALSE;
        }
        /*设置应用程序可见的设备名称*/
        devExtP->ExportString = deviceSymLink.Buffer;
        ExFreePool(deviceName.Buffer);
        return TRUE;
    }
    else
    { //IoCreateDevice调用失败,函数返回
        ExFreePool(deviceName.Buffer);
        ExFreePool(deviceSymLink.Buffer);      
        return FALSE;
    }
}
函数NPF_CreateDevice主要使用 IoCreateDevice与 IoCreateSymbolicLink系统接口函数实现。
IoCreateDevice 函数为驱动程序的使用者分配内存,并初始化一个设备对象。函数原型如下:
NTSTATUS
  IoCreateDevice(
    IN PDRIVER_OBJECT  DriverObject,
    IN ULONG  DeviceExtensionSize,
    IN PUNICODE_STRING  DeviceName  OPTIONAL,
    IN DEVICE_TYPE  DeviceType,
    IN ULONG  DeviceCharacteristics,
    IN BOOLEAN  Exclusive,
    OUT PDEVICE_OBJECT  *DeviceObject
    );
函数各参数作用如下:
参数DriverObject 为输入参数,DriverObject为指向驱动对象的指针。每个驱动程序有唯一的驱动对象与之对应,但每个驱动对象会有若干个设备对象。
参数DeviceExtensionSize为 输入参数,指定设备扩展的大小,I/O管理器会根据这个大小,在内存中创建设备对象的设备扩展。驱动程序使用该设备扩展来维护DeviceObject所描述设备I/O操作的上下文。设备扩展的内部结构由驱动程序自定义,NPF中 _DEVICE_EXTENSION的定义如下
/*包含与每个适配器关联的结构体,在该适配器上NPF被绑定*/
typedef struct _DEVICE_EXTENSION {
//适配器的名称
NDIS_STRING    AdapterName;
//设备导出的名称,比如,应用程序通过WinPcap用来打开该适配器的名称
PWSTR          ExportString;   
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
参数DeviceName为可选的输入参数,设置设备对象的名称。指向一个以0结尾的Unicode字符串,同时字符串必须为完整的路径。利用该字符串对设备对象命名。
参数DeviceType 为输入参数,描述一个系统定义的FILE_DEVICE_XXX常量,表示设备的种类(诸如FILE_DEVICE_DISK、FILE_DEVICE_KEYBOARD等)或一个厂商定义的新类型设备。NPF设置为FILE_DEVICE_TRANSPORT值。
参数DeviceCharacteristics 为输入参数,描述一个或多个系统定义的常量,各常量可位或操作。该参数提供了有关驱动设备的额外信息。其中NPF所有的值为FILE_DEVICE_SECURE_OPEN。如果设备没有任何相关特性,设为0。
参数Exclusive为输入参数,指示设备对象是否表现为一个互斥设备。也就是说,只有一个句柄在同一时刻能够发送I/O请求,同一进程的多线程能够通过一个单独的句柄发送请求。
参数DeviceObject为输出参数,如果函数调用成功,指向新创建的设备对象。一个设备对象代表驱动程序所支持的一个物理的、虚拟的或逻辑的设备。
NPF中IoCreateDevice函数返回STATUS_SUCCESS则认为函数调用成功,否则为失败。IoCreateDevice函数创建一个设备对象并返回一个指向该对象的指针。当不再需要该对象时,调用者负责调用IoDeleteDevice函数释放该对象。 NPF在卸载驱动函数NPF_Unload中释放该对象。
如果指定了设备名,只能被内核模式下的其它驱动程序所识别。但是在用户模式下的应用程序无法识别这个设备。可以通过符号连接找到该设备,使得用户模式下的应用程序能识别该设备。符号连接可以理解为设备对象起了个“别名”。设备对象的名称只能被内核模式的驱动识别,而别名已可以被用户模式下的应用程序识别。创建符号连接采用IoCreateSymbolicLink函数。
函数IoCreateSymbolicLink在一个设备对象名称与一个用户可见的名称之间建立一个符号连接。函数原型如下:
NTSTATUS
  IoCreateSymbolicLink(
    IN PUNICODE_STRING  SymbolicLinkName,
    IN PUNICODE_STRING  DeviceName
    );
参数SymbolicLinkName为输入参数,指向一个Unicode字符串,该字符串为用户可见的名称。参数DeviceName为输入参数,指向一个Unicode字符串,该字符串为驱动程序所创建设备对象的名称。
如果符号连接创建成功,IoCreateSymbolicLink函数返回 STATUS_SUCCESS。当不再需要该符号连接时,NPF在卸载驱动函数NPF_Unload中调用IoDeleteSymbolicLink函数删除该符号连接。

你可能感兴趣的:(职场,休闲,winpcap)