1.3 DriverEntry函数的具体实现
NPF的DriverEntry注册所有驱动程序的I/O回调函数、创建设备、在NDIS内把NPF定注册为一个协议驱动程序。NPF的DriverEntry函数的主要代码如下:
packetNtx\driver\packet.c 91~282
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
…
/*根据操作系统的版本,定义跳过回环数据包的正确标识*/
//获得操作系统的版本
PsGetVersion(&OsMajorVersion, &OsMinorVersion, NULL, NULL);
//根据不同的操作系统,定义跳过回环数据包的正确标识
if((OsMajorVersion == 5) && (OsMinorVersion == 0))
{ // Windows 2000 需要NDIS_FLAGS_DONT_LOOPBACK与
// NDIS_FLAGS_SKIP_LOOPBACK两个标识
g_SendPacketFlags = NDIS_FLAGS_DONT_LOOPBACK |
NDIS_FLAGS_SKIP_LOOPBACK_W2K;
}
else
{ // Windows XP、Windows 2003与后续的操作系统
//只需要NDIS_FLAGS_DONT_LOOPBACK标识
g_SendPacketFlags = NDIS_FLAGS_DONT_LOOPBACK;
}
/*初始化设备名称的前缀*/
NdisInitUnicodeString(&g_NPF_Prefix, g_NPF_PrefixBuffer);
/*获得CPU的个数,并保存该值*/
g_NCpu = NdisSystemProcessorCount();
/*零初化ProtocolChar结构体*/
RtlZeroMemory(&ProtocolChar,sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
/*向NDIS注册协议驱动程序*/
//用协议数据(版本、名称等)与回调函数地址设置ProtocolChar
#ifdef
NDIS50
ProtocolChar.MajorNdisVersion = 5;
#else
ProtocolChar.MajorNdisVersion = 3;
#endif
ProtocolChar.MinorNdisVersion = 0;
ProtocolChar.Reserved = 0;
ProtocolChar.OpenAdapterCompleteHandler = NPF_OpenAdapterComplete;
ProtocolChar.CloseAdapterCompleteHandler = NPF_CloseAdapterComplete;
ProtocolChar.SendCompleteHandler = NPF_SendComplete;
ProtocolChar.TransferDataCompleteHandler = NPF_TransferDataComplete;
ProtocolChar.ResetCompleteHandler = NPF_ResetComplete;
ProtocolChar.RequestCompleteHandler = NPF_RequestComplete;
ProtocolChar.ReceiveHandler = NPF_tap;
ProtocolChar.ReceiveCompleteHandler = NPF_ReceiveComplete;
ProtocolChar.StatusHandler = NPF_Status;
ProtocolChar.StatusCompleteHandler = NPF_StatusComplete;
#ifdef
NDIS50
ProtocolChar.BindAdapterHandler = NPF_BindAdapter;
ProtocolChar.UnbindAdapterHandler = NPF_UnbindAdapter;
ProtocolChar.PnPEventHandler = NPF_PowerChange;
ProtocolChar.ReceivePacketHandler = NULL;
#endif
ProtocolChar.Name = ProtoName;
//把NPF注册为一个NDIS协议驱动程序
NdisRegisterProtocol(
&Status,
&g_NdisProtocolHandle,
&ProtocolChar,
sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
if (Status != NDIS_STATUS_SUCCESS) {
//注册失败,函数返回
return Status;
}
/*设置IRP派遣函数和卸载例程*/
DriverObject->MajorFunction[IRP_MJ_CREATE] = NPF_Open;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = NPF_Close;
DriverObject->MajorFunction[IRP_MJ_CLEANUP]= NPF_Cleanup;
DriverObject->MajorFunction[IRP_MJ_READ] = NPF_Read;
DriverObject->MajorFunction[IRP_MJ_WRITE] = NPF_Write;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NPF_IoControl;
DriverObject->DriverUnload = NPF_Unload;// 卸载例程
/*获取系统中可用的网络适配器信息*/
bindP = getAdaptersList();
if (bindP == NULL)
{//没有找到适配器,试图复制TCP-IP的绑定
tcpBindingsP = getTcpBindings();
if (tcpBindingsP == NULL)
{//TCP-IP没有找到,函数退出
goto RegistryError;
}
bindP = (WCHAR*)tcpBindingsP;
bindT = (WCHAR*)(tcpBindingsP->Data);
}
else
{
bindT = bindP;
}
for (; *bindT != UNICODE_NULL;
bindT += (macName.Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR))
{
RtlInitUnicodeString(&macName, bindT);
NPF_CreateDevice(DriverObject, &macName);//给一个适配器创建一个设备对象
}
return STATUS_SUCCESS;
/*处理函数错误*/
RegistryError:
NdisDeregisterProtocol(
&Status,
g_NdisProtocolHandle
);
Status=STATUS_UNSUCCESSFUL;
return(Status);
1.3.1 getAdaptersList函数
函数getAdaptersList返回系统中可用的MAC链表,函数的原型如下:
PWCHAR getAdaptersList(VOID);
函数返回一个包含网络适配器链表的字符串。
该适配器链表从注册表的SYSTEM\\CurrentControlSet\\Control\\Class
\\{4D36E972-E325-11CE-BFC1-08002BE10318}注册项获取。函数首先遍历该注册表项,获取
子项的信息,再打开子项的“Linkage”子项,在“Linkage”子项下查找“Export”键名的键值,如在图5-2中,键值为“\Device\NdisWanIp”。并把键值存储到内存中,形成一个列表。函数最后返回该列表。
NPF试图从这个链表创建它的绑定。通过这种方式,它可以动态的加载或卸载,而不用通过控制面板操作。
图5-2 注册表项0006\Linkage
函数的主要代码如下:
PWCHAR getAdaptersList(void)
{
PKEY_VALUE_PARTIAL_INFORMATION result = NULL;
OBJECT_ATTRIBUTES objAttrs;
NTSTATUS status;
HANDLE keyHandle;
UINT BufPos=0;
UINT BufLen=4096;
/*分配DeviceNames所需的内存空间*/
PWCHAR DeviceNames = (PWCHAR) ExAllocatePoolWithTag(PagedPool, BufLen, '0PWA');
if (DeviceNames == NULL)
{//分配失败,函数返回
return NULL;
}
/*
*设置一个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)
{
WCHAR ExportKeyName [512];
//所打开的注册表项
PWCHAR ExportKeyPrefix =
L"\\Registry\\Machine\\System\\CurrentControlSet\\
Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\"
;
UINT ExportKeyPrefixSize =
sizeof
(L"\\Registry\\Machine\\System\\CurrentControlSet\\
Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
);
//需要打开的子项"Linkage"
PWCHAR LinkageKeyPrefix = L"\\Linkage";
UINT LinkageKeyPrefixSize = sizeof(L"\\Linkage");
//所查找的键名为"Export"
NDIS_STRING FinalExportKey = NDIS_STRING_CONST("Export");
PKEY_BASIC_INFORMATION tInfo=
(PKEY_BASIC_INFORMATION)AdapInfo;
UNICODE_STRING AdapterKeyName;
HANDLE ExportKeyHandle;
//合成要打开的注册表子项,如图5-2中的为:
//”\\Registry\\Machine\\System\\CurrentControlSet\\Control
//\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}
//\\0006\\Linkage”
RtlCopyMemory(ExportKeyName,ExportKeyPrefix,
ExportKeyPrefixSize);
RtlCopyMemory((PCHAR)ExportKeyName+ExportKeyPrefixSize,
tInfo->Name,tInfo->NameLength+2); RtlCopyMemory(
(PCHAR)ExportKeyName+ExportKeyPrefixSize+tInfo->NameLength,
LinkageKeyPrefix,LinkageKeyPrefixSize);
/*给一个Unicode字符串初始化赋值*/
RtlInitUnicodeString(&AdapterKeyName, ExportKeyName);
/*设置一个OBJECT_ATTRIBUTES类型的参数objAttrs,为了后续调用*/
InitializeObjectAttributes(&objAttrs, &AdapterKeyName,
OBJ_CASE_INSENSITIVE, NULL, NULL);
/*打开注册表表项,返回objAttrs中所描述的注册表表项的句柄*/
status=ZwOpenKey(&ExportKeyHandle,KEY_READ,&objAttrs);
if
(!NT_SUCCESS(status))
{//打开失败,跳出本次循环
continue;
}
/*查找“Export”键名的键值信息*/
status = ZwQueryValueKey(ExportKeyHandle, &FinalExportKey,
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, '1PWA');
if (valueInfoP != NULL) {
status = ZwQueryValueKey(ExportKeyHandle,
&FinalExportKey,
KeyValuePartialInformation,
valueInfoP,
valueInfoLength, &resultLength);
if (!NT_SUCCESS(status)) {
//查询失败
}
else{//查询成功
if( BufPos + valueInfoP->DataLength > BufLen ) {
//如果DeviceNames的内存空间不够,翻倍增长内存空间
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 ) { //复制“Export”键名的键值到DeviceNames中
RtlCopyMemory((PCHAR)DeviceNames+BufPos, valueInfoP->Data,valueInfoP->DataLength);
BufPos+=valueInfoP->DataLength-2;
}
}
ExFreePool(valueInfoP);
}
else {
//分配用于查询的内存失败
}
}//一次查找“Export”键名的键值信息结束
//设置结束符
DeviceNames[BufPos/2]=0;
DeviceNames[BufPos/2+1]=0;
//关闭注册表子项
ZwClose (ExportKeyHandle);
i++;
}//结束while语句
/*关闭注册表项*/
ZwClose (keyHandle);
}
/*设置函数返回内容*/
if(BufPos==0){
ExFreePool(DeviceNames);
return NULL;
}
return DeviceNames;
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的适配器。
图5-3 注册表项Tcpip\Linkage
图5-4 Bind键名的键值