Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware
Конференция «Технологии управления данными 2018»
СУБД, платформы, инструменты, реальные проекты.
29 ноября 2018 г.
2005 г.

Создание сниффера на PERL под Windows, используя модуль Win32::NetPacket

© Baranov Artem

Программы и модули, необходимые для этого, следующие.

  • WinPCAP – архитектура захвата пакетов, которая обходит стандартный стек протоколов Windows и предназначена для предоставления API соответствующим модулям PERL по захвату и отправке пакетов. Скачать соответствующий install можно с: http://www.winpcap.org/install/default.htm.
  • Модуль Win32::NetPacket – предоставляет объектно-ориентированный интерфейс к API библиотеки Packet.dll. Скачать можно либо с http://search.cpan.org, либо воспользовавшись диспетчером пакетов PERL, набрать на консоле:
    ppm install http://www.bribes.org/perl/ppm/Win32-NetPacket.ppd.

Основные методы Win32::NetPacket.

new

$nic = Win32:: NetPacket- >new ([option = > value]);

Этот метод открывает network interface card (nic – сетевой адаптер), создает объект Win32::NetPacket для этого адаптера и возвращает ссылку на этот объект. При возникновении ошибки возвращает неопределенное значение (undef), сообщение хранится в переменной $@.

Опции передаются в хеш, используя ключи и значения парами. Возможные опции:

  • adapter_name
    Устанавливает название сетевого адаптера, который будет открыт. Если эта опция не установлена, название адаптера, возвращенное функцией GetAdapterNames() используется по умолчанию. Список всех сетевых плат, установленных в системе может быть получен функцией GetAdapterNames() в контексте списка.
  • driver_buffer_size
    Задает размер, в байтах, буфера драйвера, связанного с адаптером. Значение по умолчанию - 256 килобайт. Может быть изменено позже с помощью метода SetDriverBufferSize().
  • read_timeout
    Задает время ожидания в миллисекундах, после которого метод ReceivePacket() возвратит значение, даже если не один пакет не был захвачен. Значение по умолчанию 1 секунда (1000 милисекунд). Может быть изменено позже методом SetReadTimeout().
  • min_to_copy
    Задает минимальное количество данных, в байтах, в буфере драйвера, которое заставит метод ReceivePacket() возвратить значение. Значение по умолчанию - 0. Может быть изменен позже методом SetMinToCopy(). (Работает только на системах WinNT/2000/XP)
  • mode
    Задает режим адаптера: MODE_CAPT для стандартного режима захвата или MODE_STAT для режима статистики. Подробности: см. SetMode(). Значение по умолчанию - MODE_CAPT.

SetUserBuffer

$nic->SetUserBuffer($Buffer, $size);

$Buffer - буфер, определяемый пользователем, который будет содержать захваченные данные и $size - его размер. Этот метод ничего не возвращает.

SetHwFilter

$success = $nic->SetHwFilter(CONSTANT);

Устанавливает аппаратный фильтр на входящие пакеты. Если операция была выполнена успешно метод возвращает истинное значение.

Константы, которые определяют фильтры:

    NDIS_PACKET_TYPE_DIRECTED
    NDIS_PACKET_TYPE_MULTICAST
    NDIS_PACKET_TYPE_ALL_MULTICAST
    NDIS_PACKET_TYPE_BROADCAST
    NDIS_PACKET_TYPE_SOURCE_ROUTING
    NDIS_PACKET_TYPE_PROMISCUOUS
    NDIS_PACKET_TYPE_SMT
    NDIS_PACKET_TYPE_ALL_LOCAL
    NDIS_PACKET_TYPE_MAC_FRAME
    NDIS_PACKET_TYPE_FUNCTIONAL
    NDIS_PACKET_TYPE_ALL_FUNCTIONAL
    NDIS_PACKET_TYPE_GROUP

SetReadTimeout

$success = $nic->SetReadTimeout($timeout);

Этот метод устанавливает значение времени ожидания (таймаут) чтения, связанного с $nic адаптером. $timeout содержит время в миллисекундах, после которых ReceivePacket() возвратит значение (даже, если драйвером не было захвачено ни одного пакета). Установка таймаута в 0 - отмена таймаута, то есть ReceivePacket() никогда не возвратит данные, если не придет хотя бы один пакет. Таймаут равный -1 заставляет метод ReceivePacket() возвращать значение немедленно.

Этот метод также работает, если адаптер работает в статистическом режиме, и может использоваться, чтобы установить интервал времени между двумя статистическими сообщениями.

SetMinToCopy

$success = $nic->SetMinToCopy($nbytes)

Этот метод может использоваться, чтобы определить минимальное количество данных в буфере, которое заставит драйвер реализовать чтение (т.е. метод ReceivePacket() ). $nbytes определяет это значение в байтах.

Этот метод реализован только в Windows NT/2000/XP. Драйвер для Windows 95/98/ME не поддерживает эту возможность, поэтому этот вызов осуществлен под эти системы только для совместимости.

ReceivePacket

$BytesReceived = $nic->ReceivePacket();

Этот метод выполняет захват множества пакетов. Возвращает длину части буфера, содержащую достоверные данные. Число пакетов, полученных этим методом переменно. Это зависит от количества пакетов, фактически сохраненных в буфере драйвера, от размера этих пакетов и от размера буфера, связанного с $nic. Можно установить таймаут на запросы чтения с помощью метода SetReadTimeout(). В этом случае метод возвратит значение, даже если пакеты не были захвачены, если время ожидания, установленное этим методом истекло.

Формат, используемый драйвером, чтобы послать пакеты приложению следующий:

    Пакет #1 - >    ---------           ----- bpf_hdr структура ------
                   | Bpf_hdr | --- >   | tv_sec     l = int           |
                    ---------          | tv_usec    l = int           |
                   | Данные  |         | bh_caplen  I = unsigned int  |
                    ---------          | bh_datalen I = unsigned int  |
                   | Выравнивание |    | bh_hdrlen  S = unsigned short|
    Пакет #2 - >    ---------           ------------------------------ 
                   | Bpf_hdr |
                     --------- 
                   | Данные |
                     --------- 
                   | Выравнивание |
                     --------- 
       ... И т.д

Каждый пакет имеет заголовок, находящийся в структуре bpf_hdr, которая определяет ее длину и вмещает ее временной штамп (timestamp). Поле выравнивание используется для выравнивания данных в буфере по границе слова.

Структура Bpf_hdr имеет следующие поля:

  • tv_sec
    дата захвата в стандарте времени UNIX,
  • tv_usec
    микросекунды захвата,
  • bh_caplen
    длина захваченной порции,
  • bh_datalen
    истинная длина пакета,
  • Bh_hdrlen
    длина заголовка формирующего (инкапсулирующего) пакет.

Например, можно получить значения первого заголовка буфера пользователя $buffer:

($tv_sec, $tv_usec, $caplen, $datalen, $hdrlen)=unpack ‘llIIS’, $buffer;

и затем извлечь первый пакет из этого буфера:

my $packet = substr $buffer, 0, $datalen;

GetStats

($packets_received, $packets_lost) = $nic->GetStats();

В контексте списка возвращает число пакетов, которые были получены адаптером, начиная с того времени, с которого он был открыт и количество пакетов, полученных адаптером. Пакет отбрасывается, когда пользовательское приложение не готово получить его или буфер, связанный с адаптером полон.

GetInfo

($name, $description, $type, $speed, $ip, $mask) = $nic->GetInfo();

В контексте списка возвращает: название, описание, тип, скорость в битах в секунду, IP адрес и сетевую маску $nic адаптера.

Используя вышеперечисленные методы, можно написать такую программу.

use Win32::NetPacket qw/:ndis/;
use constant SizeOfInt => 4; 
my $nic = Win32::NetPacket->new(
      driver_buffer_size => 512*1024,
      read_timeout => 0,                  
      min_to_copy => 8*1024,
   ) or die $@;
$nic->SetHwFilter(NDIS_PACKET_TYPE_PROMISCUOUS);
my $Buff;
$nic->SetUserBuffer($Buff, 128*1024);
my $BytesReceived = $nic->ReceivePacket();
my $offset = 0;
while($offset < $BytesReceived) {
      my ($tv_sec, $tv_usec, $caplen, $datalen, $hdrlen)=unpack 'llIIS', substr $Buff, $offset;
      printf "\nPacket length, captured portion: %ld, %ld\n", $datalen, $caplen;
      $offset += $hdrlen;
      my $data = substr $Buff, $offset, $datalen; # извлекаем датаграмму
      my $i;
      print map { ++$i % 16 ? "$_ " : "$_\n" } @mas=unpack( 'H2' x length( $data ), $data ),
      length( $data ) % 16 ? "\n" : '';
      $offset = (($offset+$caplen)+(SizeOfInt-1)) & ~(SizeOfInt-1);
 }

Что делать с массивом @mas, содержащим байты датаграммы, каждый решит по своему, будь то хакер или программист.

Новости мира IT:

Архив новостей

Последние комментарии:

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 985 1945361
Пресс-релизы — pr@citforum.ru
Обратная связь
Информация для авторов
Rambler's Top100 TopList liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2015 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...