Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 2005.06.06;
Скачать: [xml.tar.bz2];

Вниз

Сниффер   Найти похожие ветки 

 
JaoDa   (2005-02-04 14:54) [0]

У кого-нибудь есть сорсы сниффера под Win XP или пример работы с
библиотекой Winpcap переложенный на Delphi?

зы: у меня есть под 98-ую, которые работают с packed32.dll, но в XP они, увы, не пахают :/


 
Rouse_ ©   (2005-02-07 12:03) [1]

Вот тебе без всяких packed32.dll, но для W2000 и выше:

////////////////////////////////////////////////////////////////////////////////
//
//  ****************************************************************************
//  * Unit Name : uMain
//  * Purpose   : Демонстрационный пример сниффера.
//  * Author    : Александр (Rouse_) Багель
//  * Version   : 1.00
//  ****************************************************************************
//
//  Особая благодарность TrefptYc и группе Машина Времени,
//  за оказанную моральную поддержку, в процессе написания данного примера :)
//

unit uMain;

interface

uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls, WinSock;

const
 MAX_PACKET_SIZE = $10000; // 2^16
 SIO_RCVALL = $98000001;
 IP_HDRINCL = 16;
 WSA_VER = $202;
 MAX_ADAPTER_NAME_LENGTH        = 256;  
 MAX_ADAPTER_DESCRIPTION_LENGTH = 128;
 MAX_ADAPTER_ADDRESS_LENGTH     = 8;
 IPHelper = "iphlpapi.dll";

resourcestring
 LOG_STR_0 = "==============================================================================" + sLineBreak;
 LOG_STR_1 = "Packet ID: %-5d TTL: %d" + sLineBreak;
 LOG_STR_2 = "Packet size: %-5d bytes type: %s" + sLineBreak;
 LOG_STR_3 = "Source IP      : %15s: %d" + sLineBreak;
 LOG_STR_4 = "Destination IP : %15s: %d" + sLineBreak;
 LOG_STR_5 = "------------------------------ Packet dump -----------------------------------" + sLineBreak;

type
 USHORT = WORD;
 ULONG = DWORD;
 time_t = Longint;

 // ip заголовок
 TIPHeader = packed record
   iph_verlen:   UCHAR;    // версия и длина заголовка
   iph_tos:      UCHAR;    // тип сервиса
   iph_length:   USHORT;   // длина всего пакета
   iph_id:       USHORT;   // Идентификация
   iph_offset:   USHORT;   // флаги и смещения
   iph_ttl:      UCHAR;    // время жизни пакета
   iph_protocol: UCHAR;    // протокол
   iph_xsum:     USHORT;   // контрольная сумма
   iph_src:      ULONG;    // IP-адрес отправителя
   iph_dest:     ULONG;    // IP-адрес назначения
 end;
 PIPHeader = ^TIPHeader;

 // tcp заголовок
 TTCPHeader = packed record
   sourcePort: USHORT;       // порт отправителя
   destinationPort: USHORT;  // порт назначения
   sequenceNumber: ULONG;    // номер последовательности
   acknowledgeNumber: ULONG; // номер подтверждения
   dataoffset: UCHAR;        // смещение на область данных
   flags: UCHAR;             // флаги
   windows: USHORT;          // размер окна
   checksum: USHORT;         // контрольная сумма
   urgentPointer: USHORT;    // срочность
 end;
 PTCPHeader = ^TTCPHeader;

 // udp заголовок
 TUDPHeader = packed record
   sourcePort:       USHORT;  // порт отправителя
   destinationPort:  USHORT;  // порт назначения
   len:              USHORT;  // длина пакета
   checksum:         USHORT;  // контрольная сумма
 end;
 PUDPHeader = ^TUDPHeader;

 // Структуры для выполнения GetAdaptersInfo
 PIP_MASK_STRING = ^IP_MASK_STRING;
 IP_ADDRESS_STRING = record
   S: array [0..15] of Char;
 end;
 IP_MASK_STRING = IP_ADDRESS_STRING;

 PIP_ADDR_STRING = ^IP_ADDR_STRING;
 IP_ADDR_STRING = record
   Next: PIP_ADDR_STRING;
   IpAddress: IP_ADDRESS_STRING;
   IpMask: IP_MASK_STRING;
   Context: DWORD;
 end;

 PIP_ADAPTER_INFO = ^IP_ADAPTER_INFO;
 IP_ADAPTER_INFO = record
   Next: PIP_ADAPTER_INFO;
   ComboIndex: DWORD;
   AdapterName: array [0..MAX_ADAPTER_NAME_LENGTH + 3] of Char;
   Description: array [0..MAX_ADAPTER_DESCRIPTION_LENGTH + 3] of Char;
   AddressLength: UINT;
   Address: array [0..MAX_ADAPTER_ADDRESS_LENGTH - 1] of BYTE;
   Index: DWORD;
   Type_: UINT;
   DhcpEnabled: UINT;
   CurrentIpAddress: PIP_ADDR_STRING;
   IpAddressList: IP_ADDR_STRING;
   GatewayList: IP_ADDR_STRING;
   DhcpServer: IP_ADDR_STRING;
   HaveWins: BOOL;
   PrimaryWinsServer: IP_ADDR_STRING;
   SecondaryWinsServer: IP_ADDR_STRING;
   LeaseObtained: time_t;
   LeaseExpires: time_t;
 end;

 // Поток сниффера
 TSnifferThread = class(TThread)
 private
   WSA: TWSAData;
   hSocket: TSocket;
   Addr_in: sockaddr_in;
   Packet: array[0..MAX_PACKET_SIZE - 1] of Byte;
   LogData: String;
   procedure ShowPacket;
 protected
   function InitSocket: Boolean; virtual;
   procedure DeInitSocket(const ExitCode: Integer); virtual;
   procedure Execute; override;
   procedure ParcePacket(const PacketSize: Word); virtual;
 public
   Host: String;
 end;

 TfrmMain = class(TForm)
   btnStartStop: TButton;
   memReport: TMemo;
   cbInterfaces: TComboBox;
   Label1: TLabel;
   procedure FormCreate(Sender: TObject);
   procedure btnStartStopClick(Sender: TObject);
 private
   TotalPacketCount: Integer;
   FSnifferThread: TSnifferThread;
   procedure ReadLanInterfaces;
 end;

 // При помощи данной функции мы определим наличие сетевых интерфейсов
 // на локальном компьютере и информацию о них
 function GetAdaptersInfo(pAdapterInfo: PIP_ADAPTER_INFO;
   var pOutBufLen: ULONG): DWORD; stdcall; external IPHelper;

const
 // Размеры используемых структур
 IPHeaderSize = SizeOf(TIPHeader);
 TCPHeaderSize = SizeOf(TTCPHeader);
 UDPHeaderSize = SizeOf(TUDPHeader);

var
 frmMain: TfrmMain;

implementation


 
Rouse_ ©   (2005-02-07 12:06) [2]

{$R *.dfm}

{ TSnifferThread }

// Инициализация слушающего сокета
function TSnifferThread.InitSocket: Boolean;
var
 PromiscuousMode, HeaderInclude: Integer;
begin
 // инициализируем WinSock
 Result := WSAStartup(WSA_VER, WSA) = NOERROR;
 if not Result then
 begin
   LogData := "Ошибка: " + SysErrorMessage(WSAGetLastError);
   Synchronize(ShowPacket);
   Exit;
 end;
 // создаем сокет
 hSocket := socket(AF_INET, SOCK_RAW, IPPROTO_IP);
 if hSocket = INVALID_SOCKET then
 begin
   DeInitSocket(WSAGetLastError);
   Exit;
 end;
 FillChar(Addr_in, SizeOf(sockaddr_in), 0);
 Addr_in.sin_family:= AF_INET;
 // указываем за каким интерфейсом будем следить
 Addr_in.sin_addr.s_addr := inet_addr(PChar(Host));
 // связываем сокет с локальным адресом
 if bind(hSocket, Addr_in, SizeOf(sockaddr_in)) <> 0 then
 begin
   DeInitSocket(WSAGetLastError);
   Exit;
 end;
 // Переключаем интерфейс на прием всех пакетов проходящих через интерфейс - promiscuous mode.
 PromiscuousMode := 1;
 if ioctlsocket(hSocket, SIO_RCVALL, PromiscuousMode) <> 0 then
 begin
   DeInitSocket(WSAGetLastError);
   Exit;
 end;
 Result := True;
end;

// Завершение работы сокета
procedure TSnifferThread.DeInitSocket(const ExitCode: Integer);
begin
 // Если была ошибка - выводим ее
 if ExitCode <> 0 then
 begin
   LogData := "Ошибка: " + SysErrorMessage(ExitCode);
   Synchronize(ShowPacket);
 end;
 // Закрываем сокет
 if hSocket <> INVALID_SOCKET then closesocket(hSocket);
 // Деинициализируем WinSock
 WSACleanup;
end;

// Рабочая процедура потока сниффера
procedure TSnifferThread.Execute;
var
 PacketSize: Integer;
begin
 // Производим инициализацию
 if InitSocket then
 try
   // Крутим поток до упора
   while not Terminated do
   begin
     // Ждем получения пакета (блокирующий режим)
     PacketSize := recv(hSocket, Packet, MAX_PACKET_SIZE, 0);
     // Если есть данные - производим их разбор
     if PacketSize > SizeOf(TIPHeader) then ParcePacket(PacketSize);
   end;
 finally
   // В конце освобождаем занятые ресурсы
   DeInitSocket(NO_ERROR);
 end;
end;

// Процедура разборки пакета
procedure TSnifferThread.ParcePacket(const PacketSize: Word);
var
 IPHeader: TIPHeader;
 TCPHeader: TTCPHeader;
 UDPHeader: TUDPHeader;
 SrcPort, DestPort: Word;
 I, A, Octets, PartOctets: Integer;
 PacketType, DumpData: String;
 Addr: TInAddr;
begin
 Inc(frmMain.TotalPacketCount);
 // Читаем из буфера IP заголовок
 Move(Packet[0], IPHeader, IPHeaderSize);
 // Пишем время жизни пакета
 LogData := LOG_STR_0 +
   Format(LOG_STR_1, [frmMain.TotalPacketCount, IPHeader.iph_ttl]);
 // определяем тип протокола
 case IPHeader.iph_protocol of
   IPPROTO_TCP: // TCP
   begin
     PacketType := "TCP";
  // Читаем ТСР заголовок
     Move(Packet[IPHeaderSize], TCPHeader, TCPHeaderSize);
  // Смотрим порт отправителя и получателя
     SrcPort := TCPHeader.sourcePort;
     DestPort := TCPHeader.destinationPort;
   end;
   IPPROTO_UDP: // UDP
   begin
     PacketType := "UDP";
  // Чтаем UDP заголовок
     Move(Packet[IPHeaderSize], UDPHeader, UDPHeaderSize);
  // Смотрим порт отправителя и получателя
     SrcPort := UDPHeader.sourcePort;
     DestPort := UDPHeader.destinationPort;
   end;
 else
   PacketType := "Unsupported (0x" + IntToHex(IPHeader.iph_protocol, 2) + ")";
 end;
 // Пишем размер пакета
 LogData := LogData + Format(LOG_STR_2, [PacketSize, PacketType]);
 // Пишем IP адрес отправителя с портом
 Addr.S_addr := IPHeader.iph_src;
 LogData := LogData + Format(LOG_STR_3, [inet_ntoa(Addr), SrcPort]);
 // Пишем IP адрес получателя с портом
 Addr.S_addr := IPHeader.iph_dest;
 LogData := LogData + Format(LOG_STR_4, [inet_ntoa(Addr), DestPort]) + LOG_STR_5;

 // Выводим содержимое пакета на экран (парсинг комментировать не буду, там все просто)
 // получается что-то вроде этого:
 //
 // ------------------------------ Packet dump -----------------------------------
 // 000000 45 00 00 4E D8 91 00 00 | 80 11 DB 3B C0 A8 02 82     E..N.......;....
 // 000010 C0 A8 02 FF 00 89 00 89 | 00 3A AC 6A 83 BD 01 10     .........:.j....
 // 000020 00 01 00 00 00 00 00 00 | 20 45 43 46 46 45 49 44     ........ ECFFEID
 // 000030 44 43 41 43 41 43 41 43 | 41 43 41 43 41 43 41 43     DCACACACACACACAC
 // 000040 41 43 41 43 41 43 41 43 | 41 00 00 20 00 01           ACACACACA.. ..
 I := 0;
 Octets := 0;
 PartOctets := 0;
 while I < PacketSize do
 begin
   case PartOctets of
     0: LogData := LogData + Format("%.6d ", [Octets]);
     9: LogData := LogData + "| ";
     18:
     begin
       Inc(Octets, 10);
       PartOctets := -1;
       LogData := LogData + "    " + DumpData + sLineBreak;
       DumpData := "";
     end;
   else
     begin
       LogData := LogData + Format("%s ", [IntToHex(Packet[I], 2)]);
       if Packet[I] in [$19..$7F] then
         DumpData := DumpData + Chr(Packet[I])
       else
         DumpData := DumpData + ".";
       Inc(I);
     end;
   end;
   Inc(PartOctets);
 end;
 if PartOctets <> 0 then
 begin
   PartOctets := (16 - Length(DumpData)) * 3;
   if PartOctets >= 24 then Inc(PartOctets, 2);
   Inc(PartOctets, 4);
   LogData := LogData + StringOfChar(" ", PartOctets) +
     DumpData + sLineBreak + sLineBreak
 end
 else
   LogData := LogData + sLineBreak + sLineBreak;
 // Выводим все что напарсерили в Memo
 Synchronize(ShowPacket);
end;

procedure TSnifferThread.ShowPacket;
begin
 frmMain.memReport.Text :=
   frmMain.memReport.Text + sLineBreak + LogData;
end;


 
Rouse_ ©   (2005-02-07 12:07) [3]

{ TfrmMain }

procedure TfrmMain.FormCreate(Sender: TObject);
begin
 TotalPacketCount := 0;
 ReadLanInterfaces;
end;

// Читаем все IP адреса со всех присутствующих
// в системе сетевых интерфейсов
procedure TfrmMain.ReadLanInterfaces;
var
 InterfaceInfo,
 TmpPointer: PIP_ADAPTER_INFO;
 IP: PIP_ADDR_STRING;
 Len: ULONG;
begin
 // Смотрим сколько памяти нам требуется?
 if GetAdaptersInfo(nil, Len) = ERROR_BUFFER_OVERFLOW then
 begin
   // Берем нужное кол-во
   GetMem(InterfaceInfo, Len);
   try
     // выполнение функции
     if GetAdaptersInfo(InterfaceInfo, Len) = ERROR_SUCCESS then
     begin
       // Перечисляем все сетевые интерфейсы
       TmpPointer := InterfaceInfo;
       repeat
         // перечисляем все IP адреса каждого интерфейса
         IP := @TmpPointer.IpAddressList;
         repeat
           cbInterfaces.Items.Add(Format("%s - [%s]",
             [IP^.IpAddress.S, TmpPointer.Description]));
           IP := IP.Next;
         until IP = nil;
         TmpPointer := TmpPointer.Next;
       until TmpPointer = nil;
     end;
   finally
     // Освобождаем занятую память
     FreeMem(InterfaceInfo);
   end;
 end;
 // Смотрим - можем ли мы продолжать работу программы?
 if cbInterfaces.Items.Count = 0 then
 begin
   memReport.Text := "Сетевые интерфейсы не обнаружены." + sLineBreak +
     "Продолжение работы программы не возможно.";
   btnStartStop.Enabled := False;
   Exit;
 end
 else
   cbInterfaces.ItemIndex := 0;
end;

// Запуск остановка потока
procedure TfrmMain.btnStartStopClick(Sender: TObject);
begin
 if FSnifferThread <> nil then
 begin
   FSnifferThread.Terminate;
   FSnifferThread := nil;
   btnStartStop.Caption := "Start";
 end
 else
 begin
   FSnifferThread := TSnifferThread.Create(True);
   FSnifferThread.Host := Copy(cbInterfaces.Text, 1, Pos(" ", cbInterfaces.Text));
   FSnifferThread.FreeOnTerminate := True;
   FSnifferThread.Resume;
   btnStartStop.Caption := "Stop";
 end;
end;

end.


 
Verg ©   (2005-02-07 20:58) [4]

Первое, что бросилось в глаза:


> const
>  // Размеры используемых структур
>  IPHeaderSize : DWORD = SizeOf(TIPHeader);
>  TCPHeaderSize = SizeOf(TTCPHeader);
>  UDPHeaderSize = SizeOf(TUDPHeader);



>  Inc(frmMain.TotalPacketCount);
>  // Читаем из буфера IP заголовок
>  Move(Packet[0], IPHeader, SizeOf(TIPHeader)); // Допустим, нам не нужны опции
> IPHeaderSize := (IPHeader.iph_verlen and $F) shl 2;
>  // Пишем время жизни пакета
>  LogData := LOG_STR_0 +
>    Format(LOG_STR_1, [frmMain.TotalPacketCount, IPHeader.iph_ttl]);
>  // определяем тип протокола
...................


 
JaoDa   (2005-02-07 21:46) [5]

ваауууу и всё работает. крассотищщща!!! :))))))))) пасиб большое! :)))))))

зы: имя автора ядра обязуюсь сохранить! :)


 
Rouse_ ©   (2005-02-07 22:48) [6]

> Verg ©   (07.02.05 20:58) [4]
О, кстати, Андрей, ты не мог бы завтра выйти в асю? Я хотел с тобой именно по данному примеру проконсультироваться, да все никак тебя не застать... :(
С Ethernet заголовком небольшая проблема...
Зыранее сенькс.


 
InGo   (2005-02-15 10:56) [7]

Подскажите, а можно ли по какому-нибудь критерию в заголовке убить пакет, чтоб он дальше не прошел?


 
Verg ©   (2005-02-15 17:30) [8]


> 7] InGo   (15.02.05 10:56)
> Подскажите, а можно ли по какому-нибудь критерию в заголовке
> убить пакет, чтоб он дальше не прошел?


Что значит убить? Он (пакет) уже пришел, понимаешь? Его уже получили. Если SOCK_RAW его получил, то и все остальные его получили. Постфакт...

Если посреди комнаты кто-то крикнул, и ты этот крик услышал, то как ты можешь заставить других "забыть", про услышанный им тоже, тот же самый крик?

Снифер - это снифер, он НЕ посредник. Информация (пакеты) проходит не ЧЕРЕЗ него, а И ЕМУ ТОЖЕ.


 
atruhinov   (2005-02-17 02:13) [9]

Помогите пожайлуста!!!
Здесь уже приводился пример сниффера, я разобрался, но
прочитать Ethernet заголовок не получается.

type
 PEthernetHdr = ^TEthernetHdr;
 TEthernetHdr = packed record
   ether_dhost: TEtherAddr;            
   ether_shost: TEtherAddr;            
   ether_type: word;                    
 end;

var
 etherheader:PEthernetHdr;

begin

 iRet := recv(RawSocket, buf, sizeof(buf), 0);
 .
 .
 .
 etherheader:=PEthernetHdr(@buf);
 .
 .
 .

Выводиться блок IP но Ethernet ни в какую.
Если кто-то сталкивался с этой проблемой - помогите!!!


 
Rouse_ ©   (2005-02-25 21:51) [10]

> Ethernet
Это пример сниффера сетевого уровня а не канального...


 
Tor-3000   (2005-02-26 12:40) [11]

Rouse_
посмотри
http://forum.sources.ru/index.php?s=&showtopic=79575&hl=пакет


 
Тореро   (2005-03-13 17:56) [12]

Rouse_ можешь помочь мне, ламеру неразумному, плз ? Вот смотри. я поставил несколько фильтров, и теперь получаю сетевые пакеты только с сообщениями IRC. как мне их расшифровать и привести к нормальному тексту ? а то выдаёт чёрт знает что...


 
Тореро   (2005-03-18 07:10) [13]

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


 
Максим   (2005-03-21 14:39) [14]

Rouse_, Поздравляю !
Отличный код !


 
Максим   (2005-03-21 14:46) [15]

Rouse_, подскажите пож-ста, как ограничить пакеты только с одним портом и одним адресом ?


 
Максим   (2005-03-21 15:17) [16]

Rouse_, Хотел Вас поправить.
Порт храниться в пакете двумя байтами, в обратном порядке, поэтому надо что то вроде:
    SrcPort := Lo(TCPHeader.sourcePort)*$100+Hi(TCPHeader.sourcePort);
    DestPort := Lo(TCPHeader.destinationPort)*$100+Hi(TCPHeader.destinationPort);
вставить в процедуру ParcePacket


 
thaddy   (2005-03-21 20:40) [17]

Winpcap example (in KOL delphi, bit API same):
http://members.chello.nl/t.koning8/kolsniffer.zip


 
Verg ©   (2005-03-21 21:52) [18]


> Максим   (21.03.05 15:17) [16]


ntohs/ntohl


 
Alex Konshin ©   (2005-03-22 04:00) [19]

Тореро   (18.03.05 07:10) [13]
Подсеть в том же сегменте локалки? Если нет - то и не будет: эти пакеты вполне могут не пропускаться маршрутизатором.


 
Максим   (2005-03-22 07:49) [20]

Verg, как скажешь.
Уважаемый All, подскажите пож-ста, как добиться того, чтобы приходили только пакеты с портом 9999 (dest или src) и одним адресом, скажем 10.0.222.222 ?


 
Rouse_ ©   (2005-03-22 09:54) [21]

> Уважаемый All, подскажите пож-ста, как добиться того, чтобы приходили только пакеты с портом 9999 (dest или src) и одним адресом, скажем 10.0.222.222 ?
Так а какая разница какие приходят - ты отображай только те которые соответствуют введенным тобой условиям...


 
Максим   (2005-03-22 14:09) [22]

Rouse_, так и сделал. Думал можно некий фильтр задать при создании сокета. Оказывается, все проще.
Еще такой вопрос, мне нужно писать в БД когда приходит пакет с содержанием "$$$ logged on" (все остальное игнорить). Как думаете существенно ли где это делать ? В ShowPacket(...)  или может в ParcePacket(...) ?


 
Rouse_ ©   (2005-03-22 15:46) [23]

Разницы никакой...



Страницы: 1 вся ветка

Форум: "Сети";
Текущий архив: 2005.06.06;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.55 MB
Время: 0.013 c
14-1116701487
KilkennyCat
2005-05-21 22:51
2005.06.06
Просьба о тесте


1-1116504120
V-Isa
2005-05-19 16:02
2005.06.06
Алгоритм сортировки


14-1116517512
Jem
2005-05-19 19:45
2005.06.06
Сканер hp scanjet 2300c


4-1113392364
zsv
2005-04-13 15:39
2005.06.06
Выключение из ограниченной записи


1-1116566121
Dr. Genius
2005-05-20 09:15
2005.06.06
Доступ к HKEY_LOCAL_MACHINE





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский