65.9K
CodeProject 正在变化。 阅读更多。
Home

WLAN 扫描与 NDIS 微型端口及更多

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.57/5 (12投票s)

2007年10月29日

3分钟阅读

viewsIcon

163001

downloadIcon

6403

一篇关于从用户空间使用 NDIS 微型端口来访问 WLAN 卡的各种功能的文章

Screenshot - screen.jpg

引言

我花了一些时间研究 WLAN,我想知道 NetStumbler 是如何执行这种漂亮的扫描的,但源代码不是免费的。我编写了很多东西,但没有一个奏效。我尝试编写自己的驱动程序并使用了 WinPcap,但效果都不好。然后我阅读了一篇文章,"在 29A 杂志 8 中扫描无线网络 " 来自 GriYo。我的工作主要基于这篇文章,你可以在互联网上找到很多做同样事情的源代码。

背景

可以通过 NDIS Miniport(来自用户空间)访问 WLAN 卡的许多功能。要访问所有这些优秀的功能,你需要 Windows DDK。

看看 ntddndis.h,你会发现很多可以执行的操作。例如,你可以获取或设置 WEP 密钥。我只实现了扫描功能,但你可以改进它。要构建你自己的应用程序,你可以使用我的文章类或编写自己的类。

Using the Code

好吧,我在代码中添加了很多注释,这样你就可以轻松理解它了。你需要的所有功能都在 airctl 类中。看看头文件。

class airctl
{
    HANDLE m_handle;
    deviceInfo* m_devices;
public:
    airctl(void);
    // Frees the list of wlans
    void freeScanList(void);
    //scans for wlan and returns pointer to the list.
    NDIS_802_11_BSSID_LIST* scan(void);

bool open( char *device_name);
    //lists all devices and saves them in an internal list.
    BOOL list_devices( void);
    // return the pointer to the list
    inline deviceInfo* getDevList( ){return m_devices;};
    
public:
    ~airctl(void);
private:
    // adds one device to the list
    void AddDevice(char * desc, char * name);
    // clears the intern list
    void clearDeviceList(void);
    NDIS_802_11_BSSID_LIST* m_pBSSIDList;

    // intern used to get more information about an interface
    BOOL get_device_info(   int Index,
                        char *key_name,
                        char *device_info,
                        char *device_description);    

};

首先,我们需要一个所有设备的列表。调用 list_devices(),它会将其列在一个单链表中。然后,演示程序向用户显示所有可用设备的列表。该列表的结构如下

struct deviceInfo
{
    char *description;//information for the user
    char *name;// important to open the device
    deviceInfo* next;//single linked list
};

查看以下代码片段。它来自演示程序。

   //return me the pointer to the list
    deviceInfo* dv = win->m_airctl.getDevList();

    if (dv == NULL)
    {
        List.AddString("No available interface found !");
    }else{
        while (dv != NULL)                  //step through the linked list
        {
            List.AddString(dv->description);// adds it to the list.
            dv = dv->next;
        }
    }

用户选择一个设备后,它将被打开。

要使用 aitctl 类打开设备,我们只需要用设备名称调用 open() 即可。

    if(m_airctl.open(dv->name)!= true)
        {
            MessageBox("Cant open selected device","fehler",0);
        }else
        {
            ::AfxBeginThread( threadFunc , (LPVOID) this);

        }

但是,我们很好奇,会简单地看看这个函数。

    //we open the physical device with CreateFileA
        m_handle = CreateFileA(   device_file,
                                GENERIC_READ,
                                FILE_SHARE_READ | FILE_SHARE_WRITE,// share 
                                                                   // mode 
                                NULL,                              // default security attributes 
                                OPEN_EXISTING,                     // disposition 
                                0,                                 // file attributes
                                NULL) ;                            // do not copy file attributes

        if( m_handle == INVALID_HANDLE_VALUE)
        {
               return false;
        }
        else
        {
               // ... open
            return true;

        }

现在是时候搜索 WLAN 了。我们将从 aitctl 类中调用 scan()

        NDIS_802_11_BSSID_LIST * pBSSIDList = pDlg->m_airctl.scan();

这是如何执行的?它通过 DeviceIoControl 完成。这用于直接输入和输出,或者用于从物理设备检索信息。有关更多信息,请阅读 这篇文章。这是一系列非常好的文章。

首先,我们强制 WLAN 设备扫描 WLAN;我们等待片刻,然后再次询问设备告诉我们答案。它的源代码如下所示

     oidcode = OID_802_11_BSSID_LIST_SCAN ;//action to perform

        DeviceIoControl(        m_handle,
                                IOCTL_NDIS_QUERY_GLOBAL_STATS,
                                &oidcode,
                                sizeof( oidcode),
                                ( ULONG *) NULL,
                                0,
                                &bytesreturned,
                                NULL) ;

        Sleep( 2000) ;// we give him some time

        memset( m_pBSSIDList, 0, sizeof( NDIS_802_11_BSSID_LIST) * 
            NUMBEROF_BSSIDS) ;
        oidcode = OID_802_11_BSSID_LIST ;                     //action to perform

        if( DeviceIoControl(    m_handle,                     // device to be queried
                                IOCTL_NDIS_QUERY_GLOBAL_STATS,// operation to 
                                                              // perform
                                &oidcode,
                                sizeof( oidcode),             //  input buffer
                                ( ULONG *) m_pBSSIDList,      // output buffer
                                sizeof( NDIS_802_11_BSSID_LIST) * 
                                NUMBEROF_BSSIDS,
                                &bytesreturned,               // # bytes returned
                                NULL) == 0)                   // synchronous I/O
        {
               // List failed
              return NULL;
        }
        else {
              return m_pBSSIDList;
        }

现在我们有一个指向 NDIS_802_11_BSSID_LIST 的指针,在 ntddndis.h 中查看它的定义。

typedef struct _NDIS_802_11_BSSID_LIST
{
    ULONG           NumberOfItems;      // in list below, at least 1
    NDIS_WLAN_BSSID Bssid[1];
}

到目前为止一切顺利,但是 NDIS_WLAN_BSSID 看起来是什么样的?

typedef struct _NDIS_WLAN_BSSID
{
    ULONG                               Length;             // Length of this
                                                            // structure
    NDIS_802_11_MAC_ADDRESS             MacAddress;         // BSSID
    UCHAR                               Reserved[2];
    NDIS_802_11_SSID                    Ssid;               // SSID
    ULONG                               Privacy;            // WEP encryption
                                                            // requirement
    NDIS_802_11_RSSI                    Rssi;               // receive signal
                                                            // strength in dBm
    NDIS_802_11_NETWORK_TYPE            NetworkTypeInUse;
    NDIS_802_11_CONFIGURATION           Configuration;
    NDIS_802_11_NETWORK_INFRASTRUCTURE  InfrastructureMode;
    NDIS_802_11_RATES                   SupportedRates;
} NDIS_WLAN_BSSID, *PNDIS_WLAN_BSSID;

这个看起来好多了。这是我们想要获取的信息。现在我们可以将它们显示给用户。

但是,我们还有一件事要讨论:如何获取下一个项目。为此,我们将使用另一个指向 NDIS_WLAN_BSSID 的指针。现在变量 ULONG Length 告诉我们这个条目的长度。之后,一定数量的字节,下一个条目就 "存在"。

好吧,以下不是一个好的解决方案,但它向你展示了我的意思以及它可能的样子。

    //NumberOfItems indicates how many are now in the list
    for(unsigned int i =0 ;i < pBSSIDList->NumberOfItems;i++){
        int temp=i;        //used to build the difference
        //step to the next in list...
        PNDIS_WLAN_BSSID cpSsid=pBSSIDList->Bssid;//save
        
        //if we aren't in the first loop we have to set the pointer 
        //to the next
        while(temp!=0 ){
            // go forward
            cpSsid=(PNDIS_WLAN_BSSID)((char*)cpSsid+ cpSsid->Length);
            temp--;
        }  

        //do something with your data
    }

就是这样!感谢你的阅读,现在由你来决定。

关注点

你可以对 WLAN 设备执行更多功能。只需查看 ntddndis.h 中的 802.11 OID 即可。

历史

  • 第一个发布版本 0.1

许可证

本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。

作者可能使用的许可证列表可以在此处找到。

© . All rights reserved.