Introduction by said
============

Как только у меня в руках появился компьютер с беспроводным сетевым адаптером меня сразу заинтересовал этот тип сетей - однако в рунете к сожалению очень мало информации на эту тему (большинство статей - откровенная вода о стандартах, ничего не конкретизирующая). Беспроводные сети пока ещё не вошли в нашу жизнь так прочно, как на капиталистическом западе, однако wardriving(этим термином обозначают поездки по округе в поисках незащищённых беспроводных сетей) у нас становится всё более распространённым.

Данный туториал предстваляет собой перевод статьи Scanning for Wireless Networks By GriYo/29A, оригинал которой можно найти в 8 выпуске журнала 29A. Данная статья расчитанна на немного подготовленного читалтеля, поэтому я решил написать небольшое вступление - что бы всем была понятна терминология и сокращения, применяемые в статье. Кроме того в дополнение к статье приложенна маленькая заметка о сканировании инфракрасных сетей через функции winsock.

То что сейчас принято называть термином Wi-Fi (wireless fidelity) - это семейство спецификаций IEEE 802.11, разработанные в конце 90-х годов. В стандартах 802.11 определены принципы взаимодействия устройств в беспроводной сети.

Беспроводные сети состоят из ячеек (сот). Кажадя такая сота управляется станцией, называемой точкой доступа (AccessPoint, AP). Точка доступа и находящиеся в пределах радиуса ее действия рабочие станции с беспроводными адаптерами образуют базовую зону обслуживания (Basic Service Set, BSS). Точки доступа многосотовой сети взаимодействуют между собой через распределительную систему (Distribution System, DS). А всё это вместе (точки доступа и распределительная система) образует расширенную зону обслуживания (Extended Service Set).

Так же для обеспечения перехода между сотами предусмотренны механизмы сканирования (активного и пассивного прослушивания эфира) и присоединения (Association).

Кроме этого вам потребуются некоторые начальные знания о том как организованна поддержка сетей в Windows. Как все наверное догадываются, все сетевые протоколы реализуются через драйвера. Например драйвер TCP/IP (tcpip.sys) реализует стек протоколов TCP/IP (TCP, UDP, IP, ARP, ICMP и IGMP). Что бы каждый драйвер протокола не использовал отдельный интерфейс был придуман интерфейс TDI (Transport Driver Interface). Таким образом транспортный протокол, реализованный ввиде драйвера, называется транспортом TDI. Однако когда драйверу протокола необходимо отправить данные в сеть - ему надо их переслать непосредственно сетевому адаптеру. Для общения драйверов протокола и драйверов адаптеров была разработанна спецификация NDIS (Network Driver Interface Specification). Таким образом драйверы сетевых адаптеров, соответвующие NDIS называют драйверами NDIS или минипорт драйверами NDIS.

Что ж на этом пожалуй всё, перейдём непосредственно к сканированию сетей:

=============================================================
Scanning for Wireless Networks
By GriYo/29A

=============================================================

Introduction
============

В настоящий момент беспроводные сети получаю всё более и более широкое распространение... Пройдя от работы до дома с включённым Kismet'ом я нашёл 235 различных сетей, большинство из которых открыто для всех.

Я хочу рассказать как вы можете добавить сканирование беспроводных сетей в вашу программу без необходимости писать драйвер. Меня не волнует пишети ли вы червя, который будет распространяется через сети или просто приложение которое будет следить за вашей собственной сетью. Это ваша проблема и я не несу ответсвенности за то как вы используете эти идеи и код.

Основные преимущества этого метода:

  • Легко реализовать - тк не требуется писать драйвер.
  • Не стоит беспокоиться о различных типах карт - данный метод работает с большинством адаптеров.
Данный метод работает в XP и 2k, а так же скорее всего будет работать под более новыми версиями Windows, но я не проверял.

The device
==========
Логично, что для того что бы использовать беспроводную карту программа должна знать о ней. Обратите внимание на следующий ключ реестра:

SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards
Тут вы найдёте информацию о каждой карте, установленной в вашей системе:
Description – REG_SZ
ServiceName – REG_SZ
Следующий код показывает как вы можете воспроизвести список адаптеров, установленных в системе:
----------------------------------------------------------------------
BOOL get_device_info(   int Index,
                        char *key_name,
                        char *device_info,
                        char *device_description)
{
        HKEY hkey ;
        DWORD size ;
        DWORD type ;
        BOOL retval ;

        retval = FALSE ;

        memset( device_info, 0, SIZEOF_DEVICE_NAME) ;

        if( RegOpenKeyEx(       HKEY_LOCAL_MACHINE,
                                key_name,
                                0,
                                KEY_READ,
                                &hkey) == ERROR_SUCCESS)
        {
                type = REG_SZ ;
                size = SIZEOF_DEVICE_NAME ;

                if( RegQueryValueEx(    hkey,
                                        "ServiceName",
                                        NULL,
                                        &type,
                                        ( BYTE *) device_info,
                                        &size) == ERROR_SUCCESS)
                {
                        type = REG_SZ ;
                        size = SIZEOF_DEVICE_NAME ;

                        if( RegQueryValueEx(    hkey,
                                                "Description",
                                                NULL,
                                                &type,
                                                ( BYTE *) device_description,
                                                &size) == ERROR_SUCCESS)
                        {
                                retval = TRUE ;
                        }
                }

                RegCloseKey( hkey) ;
        }

        return retval ;
}

BOOL list_devices( void)
{
        char key_name[ SIZEOF_DEVICE_NAME] ;
        char full_name[ SIZEOF_DEVICE_NAME] ;
        char device_info[ SIZEOF_DEVICE_NAME] ;
        char device_description[ SIZEOF_DEVICE_NAME] ;

        FILETIME file_time ;

        HKEY hkey ;
        int index ;
        DWORD size ;

        index = 0 ;

        if( RegOpenKeyEx(       HKEY_LOCAL_MACHINE,
                                "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards",
                                0,
                                KEY_READ,
                                &hkey) == ERROR_SUCCESS)
        {
                size = SIZEOF_DEVICE_NAME ;

                while(  RegEnumKeyEx(   hkey,
                                        index,
                                        key_name,
                                        &size,
                                        NULL,
                                        NULL,
                                        NULL,
                                        &file_time) == ERROR_SUCCESS)
                {
                        sprintf(        full_name,
                                        "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards\\%s",
                                        key_name) ;

                        get_device_info(        index,
                                                full_name,
                                                device_info,
                                                device_description) ;

                        printf( "Index= %d\nName= %s\nDesc=%s\nKey=%s\n\n",
                                index + 1,
                                device_info,
                                device_description,
                                full_name) ;

                        index++ ;

                        size = SIZEOF_DEVICE_NAME ;
                }

                RegCloseKey( hkey) ;
        }

        if( index == 0)
        {
                printf( "No devices found\n\n") ;
        }

        return TRUE ;
}
----------------------------------------------------------------------

Open the device
===============
Для использования карты нам нужно значение ServiceName. Позвольте пользователю выбрать одно из списка или автоматически выберете его сами.

Используя значение ServiceName необходимо вызвать CreateFile что бы открыть адаптер для доступа к его возможностям. Следующая функция на входе принимет значение ServiceName и открывает устройство:

----------------------------------------------------------------------
void scan( char *device_name)
{
        HANDLE hdevice ;
        char device_file[ SIZEOF_DEVICE_NAME] ;

        sprintf( device_file, "\\\\.\\%s", device_name) ;

        hdevice = CreateFile(   device_file,
                                GENERIC_READ,
                                FILE_SHARE_READ | FILE_SHARE_WRITE,
                                NULL,
                                OPEN_EXISTING,
                                0,
                                NULL) ;

        if( hdevice == INVALID_HANDLE_VALUE)
        {
                printf( "Error: Device not available\n\n") ;
        }
        else
        {
                ...
        }

        CloseHandle( hdevice) ;
}
----------------------------------------------------------------------
Учтите что мы должны сделать имя устройства пригодным для CreateFile и преобразовать его в такой формат:
\\.\device
The IOCTL and its OID’s
=======================
А вот и главный трюк. Мы будем использовать DeviceIoControl что бы заставить наш адаптер искать доступные сети. После, используя второй вызов DeviceIoControl, мы получим буффер с результатами сканирования.

Для достижения нашей цели будем использовать IOCTL_NDIS_QUERY_GLOBAL_STATS. IOCTL(I/O control code) изначально предназначался для того, что бы Win32 программы имели ограниченный доступ к NDIS драйверу, без необходимости поддержки протокола NDIS драйвера.

Windows NT 4.0 DDK включает пример - MACADDR - в котором продемонстрированно использование IOCTL. Этот пример показывает, как используя DeviceIoControl можно получить доступ к NDIS MAC драйверу, через IOCTL_NDIS_QUERY_GLOBAL_STATS.

Для этого IOCTL имеются различные OID (object identifiers), которые могут быть нам интересны. Следующий список извлечён из файла NtDDNdis.h, входящего в DDK:

----------------------------------------------------------------------
//
// IEEE 802.11 OIDs
//
#define OID_802_11_BSSID                        0x0D010101
#define OID_802_11_SSID                         0x0D010102
#define OID_802_11_NETWORK_TYPES_SUPPORTED      0x0D010203
#define OID_802_11_NETWORK_TYPE_IN_USE          0x0D010204
#define OID_802_11_TX_POWER_LEVEL               0x0D010205
#define OID_802_11_RSSI                         0x0D010206
#define OID_802_11_RSSI_TRIGGER                 0x0D010207
#define OID_802_11_INFRASTRUCTURE_MODE          0x0D010108
#define OID_802_11_FRAGMENTATION_THRESHOLD      0x0D010209
#define OID_802_11_RTS_THRESHOLD                0x0D01020A
#define OID_802_11_NUMBER_OF_ANTENNAS           0x0D01020B
#define OID_802_11_RX_ANTENNA_SELECTED          0x0D01020C
#define OID_802_11_TX_ANTENNA_SELECTED          0x0D01020D
#define OID_802_11_SUPPORTED_RATES              0x0D01020E
#define OID_802_11_DESIRED_RATES                0x0D010210
#define OID_802_11_CONFIGURATION                0x0D010211
#define OID_802_11_STATISTICS                   0x0D020212
#define OID_802_11_ADD_WEP                      0x0D010113
#define OID_802_11_REMOVE_WEP                   0x0D010114
#define OID_802_11_DISASSOCIATE                 0x0D010115
#define OID_802_11_POWER_MODE                   0x0D010216
#define OID_802_11_BSSID_LIST                   0x0D010217
#define OID_802_11_AUTHENTICATION_MODE          0x0D010118
#define OID_802_11_PRIVACY_FILTER               0x0D010119
#define OID_802_11_BSSID_LIST_SCAN              0x0D01011A
#define OID_802_11_WEP_STATUS                   0x0D01011B
#define OID_802_11_RELOAD_DEFAULTS              0x0D01011C
----------------------------------------------------------------------
Как можно заметить - эти OID всё что нужно, что бы написать программы, способные искать беспроводные сети и отображать информацию о них.

Код ниже показывает как использовать IOCTL_NDIS_QUERY_GLOBAL_STATS совместно с OID_802_11_BSSID_LIST_SCAN и OID_802_11_BSSID_LIST, что бы получить список активных беспроводных сетей:

----------------------------------------------------------------------
ULONG oidcode ;
ULONG bytesreturned ;
NDIS_802_11_BSSID_LIST *pBSSIDList ;

pBSSIDList = ( NDIS_802_11_BSSID_LIST *) VirtualAlloc(  NULL,
                                                        sizeof( NDIS_802_11_BSSID_LIST) * NUMBEROF_BSSIDS,
                                                        MEM_RESERVE | MEM_COMMIT,
                                                        PAGE_READWRITE) ;

if( pBSSIDList == NULL)
{
        // Error: Unable to allocate memory for the list
}
else
{
        memset( pBSSIDList, 0, sizeof( NDIS_802_11_BSSID_LIST) * NUMBEROF_BSSIDS) ;
        oidcode = OID_802_11_BSSID_LIST_SCAN ;

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

        Sleep( 2000) ;

        memset( pBSSIDList, 0, sizeof( NDIS_802_11_BSSID_LIST) * NUMBEROF_BSSIDS) ;
        oidcode = OID_802_11_BSSID_LIST ;

        if( DeviceIoControl(    hdevice,
                                IOCTL_NDIS_QUERY_GLOBAL_STATS,
                                &oidcode,
                                sizeof( oidcode),
                                ( ULONG *) pBSSIDList,
                                sizeof( NDIS_802_11_BSSID_LIST) * NUMBEROF_BSSIDS,
                                &bytesreturned,
                                NULL) == 0)
        {
                // List failed
        }
        else
        {
                ...
        }
----------------------------------------------------------------------
>Из документации OID_802_11_BSSID_LIST_SCAN (взято из DDK):

Для OID_802_11_BSSID_LIST_SCAN OID необходим минипорт драйвер для 802.11 NIC для обзора BSS. С этим OID не связываются никакие данные. NIC использует следующие параметры, установленные в спецификации 802.11, в своих запросах:

  • BSSType указывает на тип инфраструктуры BSS
  • BSSID указывает что BSSID широковещательный
  • SSID указывет что SSID широковещательный
  • ScanType указывает тип сканирования - активный, пассивный или их комбинацию.
  • ChannelList указывает на все частотные каналы.
NIC использует активный, пассивный или комбинацию этих методов для сканирования в поисках сетей. Так же возможно обновлять лист BSSID в её базе данных.

NIC должен минимизировать время ответа для OID. Активный тип сканирования является предпочитаемым, когда это возможно.

База данных NIC включает BSSID для всех BSS отвечающих на частоте, которая выделенна для данного региона.

Учтите что если NIC проассоциирован с индивидуальными BSSID и SSID, которые не содержаться в списке BSSID после сканирования, описание BSSID и SSID должны быть добавленны в список BSSID в базе данных NIC.

Учтите что этот OID может вызываться очень часто (например каждые 5 секунд). Драйвер минипорта должен минимизировать время на обслуживания этого OID. Запрос этого OID не должен стать причиной, по которой NIC проассоциируется с другой точкой доступа.

И ещё из документации на OID_802_11_BSSID_LIST (опять же вырезки из DDK):

OID_802_11_BSSID_LIST OID запрашивает у драйвера минипорта список, содержащий все BSSID и их аттрибуты из 801.11 NIC базыданных. Этот список содержит все BSS, которые NIC определила в течении исследования(осмотра) BSS. На этот OID драйвер минипорта должен отвечать немедленно.

Учтите, что если этот OID вызывается когда NIC активен, без запроса OID_802_11_BSSID_LIST_SCAN, он может вернуть список BSSID, ограниченный только ID включенными в текущую конфигурацию NIC. Однако, если этот OID вызывается по крайней мере через 6 секунд после OID_802_11_BSSID_LIST_SCAN, список BSSID должен содержать все BSSID, найденные во время OID_802_11_BSSID_LIST_SCAN.

Этот OID использует структуру NDIS_802_11_BSSID_LIST, которая определяется таким образом:

----------------------------------------------------------------------
typedef_struct _NDIS_802_11_BSSID_LIST
{
ULONG  NumberOfItems;
NDIS_WLAN_BSSID  Bssid[1];
} NDIS_802_11_BSSID_LIST, *PNDIS_802_11_BSSID_LIST;
----------------------------------------------------------------------
Члены этой структуры содержат следующую информацию:
  • * NumberOfItems Указывет число элементов массива Bssid. Этот массив должен содержать по крайней мере 1 элемент.
  • * Bssid Массив из структур NDIS_WLAN_BSSID. Формат этой структуры такой:
    ----------------------------------------------------------------------
    struct _NDIS_WLAN_BSSID
    {
    ULONG  Length;
    NDIS_802_11_MAC_ADDRESS  MacAddress;
    Uchar  Reserved[2];
    NDIS_802_11_SSID  Ssid;
    ULONG  Privacy;
    NDIS_802_11_RSSI  Rssi;
    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;
    ----------------------------------------------------------------------
    
    Члены этой структуры, содержат следующую информацию:
    • Length
      Размер структуры в байтах.
    • MacAddress
      MAC адрес точки доступа.
    • Reserved
      Зарезервированно. Служит просто для выравнивания структуры.
    • Ssid
      Определяется структурой NDIS_802_11_SSID. Для получения дополнительной информации посмотрите описание этой структуры.
    • Privacy
      Указывает используется ли WEP шифрование.
    • Rssi
      Указывает Received Signal Strength Indication (RSSI) - силу полученного сигнала в децибелах.
    • NetworkTypeInUse
      Определяет тип сети. Для получения подробной информации посмотрите описание NDIS_802_11_NETWORK_TYPE.
    • Configuration
      Определяет конфгурационные параметры. Для получения подробной информации посмотрите описание OID_802_11_CONFIGURATION.
    • InfrastructureMode
      Определяет модель инфраструктуры. Для получения подробной информации посмотрите описание OID_802_11_INFRASTRUCTURE_MODE.
    • SupportedRates
      Определяет на поддерживаемые частоты. Для получения подробной информации посмотрите описание OID_802_11_SUPPORTED_RATES.
Как видно IOCTL возвращает нам много интересной информации о каждой сети в диапозоне. Используя эту информацию мы можем сделать многое. Например написать программу для wardriving'а, отображающую информацию о всех найденных беспроводных сетях .

Возможно вам захочется поэкспериментировать, используя другие OID... Кроме описанных сущестувую не менее полезные, указывающие статистическую информацию, данные о шифровании и многое, многое другое ...

Using wireless networks for viral attacks
=========================================
В последнее время вирусы и черви, использующие переполнение буффера, получили довольно широкое распространение в интернете .

Этот тип вирусов должен распространяться быстро для того что бы иметь шанс. Этот вирус должен поразить большинство целей в короткий период времени, прежде чем против него предпринят какие-либо меры противодействия (обновят программы или исправят уязвимости)

С другой стороны это может вызвать замедление сети, кучу подозрительной активности и прочее..

А теперь только представьте себе вирус, который распространяется, используя ошибки в середе менее защищённой чем интеренет: через локальные сети. Такой вирус может путешествовать от сети к сети при помощи ноутбуков например. Такой вирус может медленно переползать из одного LAN'a в другой, без каких либо заметных эффектов.

=============================================================
Scaning InfraRed Networks with WinSock
by said

=============================================================
Впервые поддержка Infrared sockets (IrSock) появилась в WindowsCE (которая со временем переименовалась в PocketPC) - а потом распространилась и на "взрослые" платформы - типа Win2k и более новые. Поэтому несмотря на подедржку в WinCE вам предоставляется меньший функционал и несмотря на то что всё сказанное в дальнейшем в какой-то степени справедливо и для WinCE - я пишу о функциях для настольных ПК.

В сетях, состоящих из устройств инфракрасной связи (их называют IrDA устройствами - Infrared Data Association), большинство компьютеров мобильны - и могут перетекать из зоны видимости одного устройства в зону другого. Поэттому традиционные механизмы здесь не уместны. Так что для интеграции IrDA в WinSock ввели специальную структуры, аналогичную sockaddr:

typedef struct sockaddr_irda{
	u_short irdaAddressFamily;
	u_char	irdaDeviceID[4];
	char	irdaServiceName[25];
} SOCKADDR_IRDA;
Поле irdaAddressFamily - всегда должно принимать значение AF_IRDA, irdaDeviceID - эта строка уникально идентифицирующая устройство и irdaServiceName - это имя службы, которую вы регистрируете или к которой пытаетесь подкдлючиться. По аналогии с TCP/IP - irdaDeviceID и irdaServiceName - можно сопоставить с парой IP адресс:порт.

Теперь рассмотрим реализацию метода перечисления всех устройств в зоне видимости адаптера (здесь и появляется разница - заголовочный файл Af_irda.h для WinCE и "нормальных" Win содержит разные определения структур). Для нумерации всех устройств используется функция - getsockopt с параметром optname=IRLMP_ENUM_DEVICES и структурой DEVICELIST как optval.

Данная структура определяется так:


typedef struct _WINDOWS_DEVICELIST
{
	ULONG                       numDevice;
	WINDOWS_IRDA_DEVICE_INFO    Device[1];
} WINDOWS_DEVICELIST, *PWINDOWS_DEVICELIST, FAR *LPWINDOWS_DEVICELIST;

typedef struct _WINDOWS_IRDA_DEVICE_INFO
{
	u_char  irdaDeviceID[4];
	char	irdaDeviceName[22];
	u_char	irdaDeviceHints1;
	u_char  irdaDeviceHints2;
	u_char  irdaCharSet;
} WINDOWS_IRDA_DEVICE_INFO, *PWINDOWS_IRDA_DEVICE_INFO, FAR *LPWINDOWS_IRDA_DEVICE_INFO;
Следующий код перечислит все IrDA устройства, находящиеся в зоне видимости:
    SOCKADDR_IRDA		irAddr = {AF_IRDA, 0, 0, 0, 0, "\0"};
    WINDOWS_DEVICELIST		devList;
    SOCKET			sock;
    DWORD			dwRetries = 0,
				dwListLen = sizeof(WINDOWS_DEVICELIST);
    DWORD			i;


    // Создаём IrDA сокет:
    sock = WSASocket(AF_IRDA, SOCK_STREAM, 0, NULL, 0,
			WSA_FLAG_OVERLAPPED);

    // Получаем список устройств в зоне видимости:
    devList.numDevice = 0;
    while ((devList.numDevice == 0) && (dwRetries <= MAX_RETRIES)){
		dwRet = getsockopt(sock, SOL_IRLMP, IRLMP_ENUMDEVICES,
			(char *)&devList, &dwListLen);
		dwRetries++;
		Sleep(1000);
    }

    // Распечатываем полученную инфу:
    for (i = 0; i < devList.numDevice; i++){
		printf("Device: %d\n", i);
		printf("\tDevice ID: %x%x%x%x\n", 
			devList.Device[i].irdaDeviceID[0],
	    devList.Device[i].irdaDeviceID[1],
	    devList.Device[i].irdaDeviceID[2],
	    devList.Device[i].irdaDeviceID[3]);
		printf("\tDevice Name: %s\n", devList.Device[i].irdaDeviceName);		
    } 

    closesocket(sock);
Перед вызовом getsockopt необходимо присвоить numDevice значение равное 0, после вызова в этом поле будет содержаться число структур IRDA_DEVICE_INFO в поле Device.

Outro
=========================================
Что надеюсь теперь вы поняли как включить поддрежку беспроводных сетей в ваши программы. В архиве вы найдёте следующие вещи:

  • Оригинал статьи Scanning for Wireless Networks
  • Файл Af_irda.h - для тех у кого его не хватает ;)
Автор: said /7.02.05/ ©

Mazafaka.Ru - E-Zine - 2005 ©