jjzjj

c - 如何在 NDIS 6 过滤器驱动程序中启用 802.11 监控模式 (DOT11_OPERATION_MODE_NETWORK_MONITOR)?

coder 2024-06-12 原文

我已将 WinPcap 移植到 NDIS 6 过滤器驱动程序:https://github.com/nmap/npcap .但它仍然不支持捕获所有 802.11 native 数据包(如未捕获控制和管理帧)。

我注意到有一种方法可以使用WlanSetInterface 函数为无线适配器设置DOT11_OPERATION_MODE_NETWORK_MONITOR。但是这次调用成功了(返回值是OK的,这次调用后我的wifi网络断开了)。但问题是我无法使用 Wireshark 在 Wi-Fi 接口(interface)上看到任何数据包,甚至连假以太网形式的 802.11 数据也看不到。所以肯定有问题。

我知道从 NDIS 6 和 vista 开始,启用此功能是可能的(至少微软自己的 Network Monitor 3.4 支持此功能)。

所以我想知道如何为 NDIS 6 版本的 WinPcap 启用监控模式?谢谢。

我的代码如下所示:

// WlanTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <wlanapi.h>

#define WLAN_CLIENT_VERSION_VISTA 2

void SetInterface(WLAN_INTF_OPCODE opcode, PVOID* pData, GUID* InterfaceGuid)
{
    DWORD dwResult = 0;
    HANDLE hClient = NULL;
    DWORD dwCurVersion = 0;
    DWORD outsize = 0;

    // Open Handle for the set operation
    dwResult = WlanOpenHandle(WLAN_CLIENT_VERSION_VISTA, NULL, &dwCurVersion, &hClient);
    dwResult = WlanSetInterface(hClient, InterfaceGuid, opcode, sizeof(ULONG), pData, NULL);
    WlanCloseHandle(hClient, NULL);

}

// enumerate wireless interfaces
UINT EnumInterface(HANDLE hClient, WLAN_INTERFACE_INFO sInfo[64])
{
    DWORD dwError = ERROR_SUCCESS;
    PWLAN_INTERFACE_INFO_LIST pIntfList = NULL;
    UINT i = 0;

    __try
    {
        // enumerate wireless interfaces
        if ((dwError = WlanEnumInterfaces(
            hClient,
            NULL,               // reserved
            &pIntfList
            )) != ERROR_SUCCESS)
        {
            __leave;
        }

        // print out interface information
        for (i = 0; i < pIntfList->dwNumberOfItems; i++)
        {
            memcpy(&sInfo[i], &pIntfList->InterfaceInfo[i], sizeof(WLAN_INTERFACE_INFO));
        }

        return pIntfList->dwNumberOfItems;
    }
    __finally
    {
        // clean up
        if (pIntfList != NULL)
        {
            WlanFreeMemory(pIntfList);
        }
    }
    return 0;
}

// open a WLAN client handle and check version
DWORD
OpenHandleAndCheckVersion(
    PHANDLE phClient
    )
{
    DWORD dwError = ERROR_SUCCESS;
    DWORD dwServiceVersion;
    HANDLE hClient = NULL;

    __try
    {
        *phClient = NULL;

        // open a handle to the service
        if ((dwError = WlanOpenHandle(
            WLAN_API_VERSION,
            NULL,               // reserved
            &dwServiceVersion,
            &hClient
            )) != ERROR_SUCCESS)
        {
            __leave;
        }

        // check service version
        if (WLAN_API_VERSION_MAJOR(dwServiceVersion) < WLAN_API_VERSION_MAJOR(WLAN_API_VERSION_2_0))
        {
            // No-op, because the version check is for demonstration purpose only.
            // You can add your own logic here.
        }

        *phClient = hClient;

        // set hClient to NULL so it will not be closed
        hClient = NULL;
    }
    __finally
    {
        if (hClient != NULL)
        {
            // clean up
            WlanCloseHandle(
                hClient,
                NULL            // reserved
                );
        }
    }

    return dwError;
}

// get interface state string
LPWSTR
GetInterfaceStateString(__in WLAN_INTERFACE_STATE wlanInterfaceState)
{
    LPWSTR strRetCode;

    switch (wlanInterfaceState)
    {
    case wlan_interface_state_not_ready:
        strRetCode = L"\"not ready\"";
        break;
    case wlan_interface_state_connected:
        strRetCode = L"\"connected\"";
        break;
    case wlan_interface_state_ad_hoc_network_formed:
        strRetCode = L"\"ad hoc network formed\"";
        break;
    case wlan_interface_state_disconnecting:
        strRetCode = L"\"disconnecting\"";
        break;
    case wlan_interface_state_disconnected:
        strRetCode = L"\"disconnected\"";
        break;
    case wlan_interface_state_associating:
        strRetCode = L"\"associating\"";
        break;
    case wlan_interface_state_discovering:
        strRetCode = L"\"discovering\"";
        break;
    case wlan_interface_state_authenticating:
        strRetCode = L"\"authenticating\"";
        break;
    default:
        strRetCode = L"\"invalid interface state\"";
    }

    return strRetCode;
}

int main()
{
    HANDLE hClient = NULL;
    WLAN_INTERFACE_INFO sInfo[64];
    RPC_CSTR strGuid = NULL;

    TCHAR szBuffer[256];
    DWORD dwRead;
    if (OpenHandleAndCheckVersion(&hClient) != ERROR_SUCCESS)
        return -1;

    UINT nCount = EnumInterface(hClient, sInfo);
    for (UINT i = 0; i < nCount; ++i)
    {
        if (UuidToStringA(&sInfo[i].InterfaceGuid, &strGuid) == RPC_S_OK)
        {
            printf(("%d. %s\n\tDescription: %S\n\tState: %S\n"),
                i,
                strGuid,
                sInfo[i].strInterfaceDescription,
                GetInterfaceStateString(sInfo[i].isState));

            RpcStringFreeA(&strGuid);
        }
    }

    UINT nChoice = 0;
//  printf("for choice wireless card:");
// 
//  if (ReadConsole(GetStdHandle(STD_INPUT_HANDLE), szBuffer, _countof(szBuffer), &dwRead, NULL) == FALSE)
//  {
//      puts("error input");
//      return -1;
//  }
//  szBuffer[dwRead] = 0;
//  nChoice = _ttoi(szBuffer);
// 
//  if (nChoice > nCount)
//  {
//      puts("error input.");
//      return -1;
//  }

    //ULONG targetOperationMode = DOT11_OPERATION_MODE_EXTENSIBLE_STATION;
    ULONG targetOperationMode = DOT11_OPERATION_MODE_NETWORK_MONITOR;

    SetInterface(wlan_intf_opcode_current_operation_mode, (PVOID*)&targetOperationMode, &sInfo[nChoice].InterfaceGuid);

    return 0;
}

更新:

Guy 让我清楚了 WinPcap 的高级库端应该如何处理监控模式,本质上是设置/获取 OID 值。但是WinPcap驱动怎么办,需要换驱动吗?我认为 WlanSetInterface 调用实际上与使用 OID 请求设置 DOT11_OPERATION_MODE_NETWORK_MONITOR 做同样的事情?它不起作用的事实是否意味着 npf 驱动程序也需要某种更改?

最佳答案

(针对问题更新和后续评论更新了答案。)

使用master分支libpcap版本pcap-win32.c中的pcap_oid_set_request_win32()来进行OID设置/获取操作。如果在 pcap_activate_win32() 中设置了 p->opt.rfmon,请将 OID OID_DOT11_CURRENT_OPERATION_MODE 设置为 DOT11_CURRENT_OPERATION_MODE structure uCurrentOpMode 设置为 DOT11_OPERATION_MODE_NETWORK_MONITOR

对于 pcap_can_set_rfmon_win32(),尝试获取设备的句柄(请注意,这是在激活调用之前完成的),如果成功,则使用 pcap_oid_get_request_win32() 尝试获取该 OID 的值;如果成功,则可以设置,否则,要么不能设置,要么报错。

驱动程序已经支持通用的获取/设置 OID 操作 - 这就是 PacketRequest() 使用的,以及 pcap_oid_get_request_win32()/pcap_oid_set_request_win32() 是在 PacketRequest() 之上实现的,所以这就是它们所使用的。

作为I indicated在线程中的消息中 you started在 wireshark-dev 列表上,处理来自 NDIS 的接收指示的代码必须能够处理“原始数据包”接收指示,并且您可能还必须将它们添加到 NDIS 数据包过滤器。 ( And you'll have to hack dumpcap, if you're going to use Wireshark to test the changes ;您将无法更改 NPcap,以便人们可以将其放入,现有版本的 Wireshark 将支持监控模式。)

我也在那里指出了how to query a device to find out whether it supports monitor mode .

至于关闭监控模式,这需要驱动程序、packet.dll 和 libpcap 的工作。在驱动程序中:

  • 在 NDIS 6 驱动程序中,对于每个接口(interface),都有“监控模式实例”的计数和保存的操作模式,并且对于接口(interface)的每个打开的 NPF 实例,都有一个“监控模式”标志;
  • 在 Windows 9x 和 NDIS 4/5 驱动程序中,添加一个“打开监控模式”BIOC 调用,该调用总是失败并返回 ERROR_NOT_SUPPORTED
  • 在 NDIS 6 驱动程序中,添加相同的 BIOC 调用,如果未设置实例的“监控模式”标志,则尝试将操作模式设置为监控模式,如果它成功,如果接口(interface)的监控模式计数为零,则保存旧的操作模式,增加接口(interface)的监控模式计数并设置实例的“监控模式”标志(它也可以将适当的值添加到数据包过滤器);
  • 让关闭打开的 NPF 实例的例程检查实例的“监控模式”标志,如果已设置,则减少“监控模式实例”计数,如果计数达到零,则恢复旧的操作模式。

在 packet.dll 中,添加一个 PacketSetMonitorMode() 例程,它是对相关 BIOC ioctl 的包装。

pcap-win32.c 中,如果请求监控模式,则调用 PacketSetMonitorMode(),而不是直接设置操作模式。

要在驱动程序中设置 OID,请参阅 NPF_IoControl()BIOCQUERYOIDBIOCSETOID 的代码路径 - 新的 BIOC ioctl 将在 NPF_IoControl() 中处理。

(当然,还要进行适当的 MP 锁定。)

如果您可以枚举接口(interface)的所有 NPF 实例,则可能不需要监控模式计数 - 计数只是设置了监控模式标志的实例数。

在驱动程序中执行此操作意味着如果执行监控模式捕获的程序突然终止,因此没有用户模式代码进行任何清理,该模式仍然可以重置。

关于c - 如何在 NDIS 6 过滤器驱动程序中启用 802.11 监控模式 (DOT11_OPERATION_MODE_NETWORK_MONITOR)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34507789/

有关c - 如何在 NDIS 6 过滤器驱动程序中启用 802.11 监控模式 (DOT11_OPERATION_MODE_NETWORK_MONITOR)?的更多相关文章

  1. ruby - 如何在 Ruby 中顺序创建 PI - 2

    出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

  2. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  3. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  4. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  5. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  6. ruby - 在 Ruby 中编写命令行实用程序 - 2

    我想用ruby​​编写一个小的命令行实用程序并将其作为gem分发。我知道安装后,Guard、Sass和Thor等某些gem可以从命令行自行运行。为了让gem像二进制文件一样可用,我需要在我的gemspec中指定什么。 最佳答案 Gem::Specification.newdo|s|...s.executable='name_of_executable'...endhttp://docs.rubygems.org/read/chapter/20 关于ruby-在Ruby中编写命令行实用程序

  7. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  8. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  9. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  10. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

随机推荐