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






3.57/5 (12投票s)
2007年10月29日
3分钟阅读

163001

6403
一篇关于从用户空间使用 NDIS 微型端口来访问 WLAN 卡的各种功能的文章
引言
我花了一些时间研究 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
许可证
本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。
作者可能使用的许可证列表可以在此处找到。