Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.06.06;
Скачать: CL | DM;

Вниз

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

 
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;
Скачать: CL | DM;

Наверх




Память: 0.56 MB
Время: 0.056 c
1-1116523039
Petro_
2005-05-19 21:17
2005.06.06
Mdi и края формы в Windows XP


3-1114680917
Bocman
2005-04-28 13:35
2005.06.06
автоинкремент в Paradox


6-1111485142
frEE)stylEr
2005-03-22 12:52
2005.06.06
определение имени подключения


1-1116137905
Grief
2005-05-15 10:18
2005.06.06
var Proc: procedure а дальше что?!


6-1111352201
redlord
2005-03-20 23:56
2005.06.06
охрана блокированного сокета