在Windows 8下不调用NDIS筛选器驱动程序的FilterAttach例程

每一个人。 我已将NDIS 5协议中着名的数据包捕获软件WinPcap移植到NDIS 6 LWF。 在Win7下一切都很好。 但是,在Win8下永远不会调用FilterAttach例程。 我发现在DriverEntry中调用NdisFRegisterFilterDriver返回NDIS_STATUS_SUCCESS,这太奇怪了。 谁能帮我? 谢谢!

这是DriverEntry的代码

_Use_decl_annotations_ NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { NDIS_FILTER_DRIVER_CHARACTERISTICS FChars; NTSTATUS Status = STATUS_SUCCESS; // NDIS_STRING FriendlyName = NDIS_STRING_CONST("WinPcap NDIS LightWeight Filter"); // NDIS_STRING UniqueName = NDIS_STRING_CONST("{5cbf81bd-5055-47cd-9055-a76b2b4e2637}"); //unique name, quid name // NDIS_STRING ServiceName = NDIS_STRING_CONST("npf6x"); //this to match the service name in the INF NDIS_STRING FriendlyName = RTL_CONSTANT_STRING(L"WinPcap NDIS LightWeight Filter"); NDIS_STRING UniqueName = RTL_CONSTANT_STRING(L"{5cbf81bd-5055-47cd-9055-a76b2b4e2637}"); //unique name, quid name NDIS_STRING ServiceName = RTL_CONSTANT_STRING(L"npf6x"); //this to match the service name in the INF WCHAR* bindT; PKEY_VALUE_PARTIAL_INFORMATION tcpBindingsP; UNICODE_STRING macName; ULONG OsMajorVersion, OsMinorVersion; TRACE_ENTER(); UNREFERENCED_PARAMETER(RegistryPath); FilterDriverObject = DriverObject; // // Get OS version and store it in a global variable. // // Note: both RtlGetVersion() and PsGetVersion() are documented to always return success. // // OsVersion.dwOSVersionInfoSize = sizeof(OsVersion); // RtlGetVersion(&OsVersion); // PsGetVersion(&OsMajorVersion, &OsMinorVersion, NULL, NULL); TRACE_MESSAGE2(PACKET_DEBUG_INIT, "OS Version: %d.%d\n", OsMajorVersion, OsMinorVersion); NdisInitUnicodeString(&g_NPF_Prefix, g_NPF_PrefixBuffer); // // Get number of CPUs and save it // #ifdef NDIS620 g_NCpu = NdisGroupMaxProcessorCount(ALL_PROCESSOR_GROUPS); #else g_NCpu = NdisSystemProcessorCount(); #endif // // TODO: Most handlers are optional, however, this sample includes them // all for illustrative purposes. If you do not need a particular // handler, set it to NULL and NDIS will more efficiently pass the // operation through on your behalf. // // // Register as a service with NDIS // NdisZeroMemory(&FChars, sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS)); FChars.Header.Type = NDIS_OBJECT_TYPE_FILTER_DRIVER_CHARACTERISTICS; FChars.Header.Size = sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS); #if NDIS_SUPPORT_NDIS61 FChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_2; #else FChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_1; #endif FChars.MajorNdisVersion = NDIS_FILTER_MAJOR_VERSION; FChars.MinorNdisVersion = NDIS_FILTER_MINOR_VERSION; FChars.MajorDriverVersion = 1; FChars.MinorDriverVersion = 0; FChars.Flags = 0; FChars.FriendlyName = FriendlyName; FChars.UniqueName = UniqueName; FChars.ServiceName = ServiceName; FChars.SetOptionsHandler = NPF_RegisterOptions; FChars.AttachHandler = NPF_Attach; FChars.DetachHandler = NPF_Detach; FChars.RestartHandler = NPF_Restart; FChars.PauseHandler = NPF_Pause; FChars.SetFilterModuleOptionsHandler = NPF_SetModuleOptions; FChars.OidRequestHandler = NPF_OidRequest; FChars.OidRequestCompleteHandler = NPF_OidRequestComplete; FChars.CancelOidRequestHandler = NPF_CancelOidRequest; FChars.SendNetBufferListsHandler = NPF_SendEx; FChars.ReturnNetBufferListsHandler = NPF_ReturnEx; FChars.SendNetBufferListsCompleteHandler = NPF_SendCompleteEx; FChars.ReceiveNetBufferListsHandler = NPF_TapEx; FChars.DevicePnPEventNotifyHandler = NPF_DevicePnPEventNotify; FChars.NetPnPEventHandler = NPF_NetPnPEvent; FChars.StatusHandler = NPF_Status; FChars.CancelSendNetBufferListsHandler = NPF_CancelSendNetBufferLists; DriverObject->DriverUnload = NPF_Unload; // // Initialize spin locks // //NdisAllocateSpinLock(&FilterListLock); //InitializeListHead(&FilterModuleList); // // Standard device driver entry points stuff. // DriverObject->MajorFunction[IRP_MJ_CREATE] = NPF_OpenAdapter; DriverObject->MajorFunction[IRP_MJ_CLOSE] = NPF_CloseAdapter; 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; bindP = getAdaptersList(); if (bindP == NULL) { TRACE_MESSAGE(PACKET_DEBUG_INIT, "Adapters not found in the registry, try to copy the bindings of TCP-IP."); tcpBindingsP = getTcpBindings(); if (tcpBindingsP == NULL) { TRACE_MESSAGE(PACKET_DEBUG_INIT, "TCP-IP not found, quitting."); 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); } Status = NdisFRegisterFilterDriver(DriverObject, (NDIS_HANDLE) FilterDriverObject, &FChars, &FilterDriverHandle); if (Status != NDIS_STATUS_SUCCESS) { TRACE_MESSAGE(PACKET_DEBUG_INIT, "Failed to register filter with NDIS."); TRACE_EXIT(); return Status; } TRACE_EXIT(); return STATUS_SUCCESS; RegistryError : NdisFDeregisterFilterDriver(FilterDriverHandle); Status = STATUS_UNSUCCESSFUL; TRACE_EXIT(); return(Status); } 

为什么不调用FilterAttach例程 – 我不知道。 我想不出Windows 7和Windows 8之间的任何显着差异。(另一方面,Windows 8.1 Preview确实有一些实质性的绑定更改。)

检查filter是否绑定在usermode中。 使用powershell中的Get-NetAdapterBinding来确保从NIC到filter的绑定,以及绑定已启用。

validation微型端口是否正常启动。 使用!ndiskd.miniport查看微型端口是否正常绑定。 检查您的filter是否列在微型端口的filter绑定列表中。

几个不相关的笔记:

  • 我不认为RegistryError标签应该调用NdisFDeregisterFilterDriver ,因为filter还没有注册到NDIS。
  • getAdaptersListgetTcpBindings这样的代码听起来很可怕,但我想这可能是旧驱动程序中预先存在的代码。 请注意,我们不支持在注册表中进行搜索,而是希望在usermode中使用INetCfg来发现适配器。 对于LWF,我们希望您的filter始终绑定到所有function适配器。 如果需要考虑perf,则LWF可以根据需要使用NdisFRestartFilterNdisSetOptionalHandlers动态地将其自身插入/移除到数据路径中。

感谢您在评论中提供的其他诊断信息。 您对问题的描述使我可以将其视为Windows中的错误。

首次安装筛选器时会出现此问题。 在某些情况下,如果filter驱动程序尚未在kernelmode中启动,则NDIS可能会忽略微型端口上的绑定已更改的通知。

有几种解决方法 – 正如您所指出的,一种解决方法是更改​​filter的StartType。 另一种解决方法是使用INetCfg在安装后禁用并重新启用每个微型端口的filter绑定。 您也可以禁用和重新启用微型端口,或重新启动计算机,尽管这些是相当具有破坏性的解决方法。

✓此错误不会影响Windows 7。
✗此错误会影响Windows 8和Windows Server 2012。
✓此错误不会影响Windows 8.1和Windows Server 2012 R2。 (我在清理NDIS中的一些代码时不知不觉地修复了这个错误。)

如果您不能等待免费的Windows 8.1更新推广到所有Windows 8计算机 ,则可以联系Microsoft WDK支持。 请参考WindowsSE:452306,以便他们可以找到有关该问题的笔记,或让他们在内部与我联系。

 // // DisableEnableBindings // // Purpose: This code can be used to quickly disable/enable all bindings to a particular // NDIS protocol or filter. // // Usage: Run this and provide the name of a NetCfg component. For example, "ms_pacer". #include  #include  #include  #include  #include  #include  #define MY_APP_NAME L"DisableEnableBindings test app" bool RestartAllBindings(INetCfg *netcfg, PCWSTR name) { HRESULT hr; CComPtr comp; CComPtr bindings; hr = netcfg->FindComponent(name, &comp); if (FAILED(hr)) { wprintf(L"INetCfg::FindComponent 0x%08x\n", hr); return false; } hr = comp.QueryInterface(&bindings); if (FAILED(hr)) { wprintf(L"QueryInterface(INetCfgComponentBindings) 0x%08x\n", hr); return false; } CComPtr enumerator; hr = bindings->EnumBindingPaths(EBP_BELOW, &enumerator); if (FAILED(hr)) { wprintf(L"INetCfgComponentBindings::EnumBindingPaths 0x%08x\n", hr); return false; } // Loop over all bindings that involve this component while (true) { CComPtr path; hr = enumerator->Next(1, &path, nullptr); if (hr == S_FALSE) { // Reached end of list; quit. break; } if (FAILED(hr)) { wprintf(L"IEnumNetCfgBindingPath::Next 0x%08x\n", hr); return false; } PWSTR token = nullptr; hr = path->GetPathToken(&token); if (FAILED(hr)) { wprintf(L"INetCfgBindingPath::GetPathToken 0x%08x\n", hr); continue; } wprintf(L"Found binding %s\n", token); CoTaskMemFree(token); hr = path->IsEnabled(); if (FAILED(hr)) { wprintf(L"INetCfgBindingPath::IsEnabled 0x%08x\n", hr); continue; } if (S_FALSE == hr) { wprintf(L"\tPath is already disabled. Skipping over it.\n"); continue; } // Diable hr = path->Enable(FALSE); if (FAILED(hr)) { wprintf(L"INetCfgBindingPath::Enable(FALSE) 0x%8x\n", hr); continue; } hr = netcfg->Apply(); if (FAILED(hr)) { wprintf(L"INetCfg::Apply 0x%08x\n", hr); return false; } wprintf(L"\tPath disabled\n"); // Enable hr = path->Enable(TRUE); if (FAILED(hr)) { wprintf(L"INetCfgBindingPath::Enable(TRUE) 0x%8x\n", hr); return false; } hr = netcfg->Apply(); if (FAILED(hr)) { wprintf(L"INetCfg::Apply 0x%08x\n", hr); return false; } wprintf(L"\tPath enabled\n"); } return true; } bool ConnectToNetCfg(PCWSTR name) { HRESULT hr; CComPtr netcfg; CComPtr lock; // Before we can get started, we need to do some initialization work. hr = netcfg.CoCreateInstance(CLSID_CNetCfg); if (FAILED(hr)) { wprintf(L"CoCreateInstance(CLSID_CNetCfg 0x%08x\n", hr); return false; } hr = netcfg.QueryInterface(&lock); if (FAILED(hr)) { wprintf(L"QueryInterface(INetCfgLock) 0x%08x\n", hr); return false; } // Note that this call can block. hr = lock->AcquireWriteLock(INFINITE, MY_APP_NAME, nullptr); if (FAILED(hr)) { wprintf(L"INetCfgLock::AcquireWriteLock 0x%08x\n", hr); return false; } hr = netcfg->Initialize(nullptr); if (FAILED(hr)) { wprintf(L"INetCfg::Initialize 0x%08x\n", hr); return false; } bool ok = RestartAllBindings(netcfg.p, name); hr = netcfg->Uninitialize(); if (FAILED(hr)) { wprintf(L"INetCfg::Uninitialize 0x%08x\n", hr); } hr = lock->ReleaseWriteLock(); if (FAILED(hr)) { wprintf(L"INetCfgLock::ReleaseWriteLock 0x%08x\n", hr); } return ok; } int wmain(int argc, wchar_t **argv) { if (argc != 2) { wprintf(L"Usage: DisableEnableBindings \n"); return 2; } PCWSTR name = argv[1]; CComPtr netcfg; CComPtr lock; HRESULT hr; hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); if (FAILED(hr)) { wprintf(L"CoInitializeEx 0x%08x\n", hr); return 1; } bool ok = ConnectToNetCfg(name); CoUninitialize(); wprintf(ok ? L"Succeeded.\n" : L"Failed.\n"); return ok ? 0 : 1; }