/*-----------------------------------------------------------------------*/
 /*                       R I N G 0,    I S S U E   # 1                   */
 /*-----------------------------------------------------------------------*/

                      Написание снифферов под win32

                                                          by CNerd/HangUP

  Пришло  наконец  время  поговорить  (и  поделать)  о написании пакетных
 снифферов   под   Win32.  Для  чего  нужен  сниффер?  Спектр  применений
 необычайно  разнообразен... ;) Это может быть как анализ своего трафика,
 так  и  тотальное  выснифывание  какой-нибудь здоровенной локалки/узла в
 целях  отлова  паролей,  установка на удаленную машину, ... etc. В любом
 случае     удобно,     чтобы     отловленные     пакеты    склеивались и
 систематизировались  по  хостам и портам, формируя единую полоску данных
 для каждого порта.

  Сделаем  так:  систематизация  по  хостам  будет  происходить  за  счет
 создания  директорий  с  именами  вида IP1-IP2, а уже в этих директориях
 будут  создаваться  файлы  типа  Port1-Port2 (локальный и удаленный те).
 Соответственно  весь  трафик по данной паре портов сливается в сей файл.
 По  моему, весьма удобно. Перейдем к техническим деталям. Для реализации
 этой        зловредной        затеи,        потребуется        WinPCap -
 http://netgroup-serv.polito.it/winpcap  . Скачивайте и устанавливайте. В
 комлект  входит  необходимый  драйвер,  инклюдники  и lib файлы для VC +
 несколько полезных примеров.

  Если  вы  используете другой компилер, например (lcc-win32 - именно его
 юзаю  я),  то  нихрена  вам  эти  lib'ы  не подойдут. Создайте свой exp,
 используя

 implib packet.dll > packet.exp

  для получения списка функций. В начале файла 3 строки:

 No .edata section in DLL
 Export table in .rdata section offset 0x6000
 Reading Packet.dll

  ...  удалите  нафиг,  заменив  их  на  просто PACKET.DLL и кормите этим
 файлом buildlib:

 buildlib packet.exp

  Все, lib готов, двигаемся дальше, к собственно исходнику.

#include < windows.h >
#include < winsock.h >
#include < Packet32.h >

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

 HANDLE hndl;
 HWND hwnd;

 LPADAPTER  lpAdapter = 0;
 LPPACKET   lpPacket;

 //unicode strings (winnt)
 WCHAR AdapterName[512]; // список адаптеров
 WCHAR *temp,*temp1;

 //ascii strings   (win9x)
 char AdapterNamea[512]; // он же, но для Win9x
 char *tempa,*temp1a;

 char AdapterList[10][1024];
 char b1[65535],b2[65535],b3[65535];
 char buffer[256000];  // cюда сливается то, что прислал драйвер

 int   AdapterNum=0,i;
 ULONG AdapterLength;

 struct bpf_stat stat;

/*- Разбор пакетов -*/

void packets(LPPACKET lpPacket)
{
 ULONG        i, recv;
 u_int  off=0,hlen,tlen;
 struct bpf_hdr *hdr;
 char   *pack, *data, *buf;

 recv = lpPacket->ulBytesReceived;
 buf  = lpPacket->Buffer;

 while (off < recv) // крутим цикл, пока не кончатся пакеты в буфере
 {
  hdr=(struct bpf_hdr *)(buf+off);
  tlen=hdr->bh_datalen;
  hlen=hdr->bh_hdrlen;

  off+=hdr->bh_hdrlen;
  pack = (char*)(buf+off);

  if ((pack[23] == 6) && (tlen > 54)) // это TCP больше 54 байт?
  {
   data = (char*)(buf+off+54); // собственное данные из пакета
                               // (заголовок срезан)

    // выковыриваем SRC и DEST IP

   IN_ADDR ia[2];
   ia[1].s_addr=MAKELONG(MAKEWORD(pack[26],pack[27]), \
    MAKEWORD(pack[28],pack[29]));
   ia[2].s_addr=MAKELONG(MAKEWORD(pack[30],pack[31]), \
    MAKEWORD(pack[32],pack[33]));

    // выковыриваем local и remote порты

   int p[2];
   p[1]=MAKEWORD(pack[35],pack[34]);
   p[2]=MAKEWORD(pack[37],pack[36]);

    // этот финт ушами расчитан на то, чтоб вместо двух каталогов
    // IP1-IP2 и IP2-IP1 создавался один IP1-IP2 с указанными
    // направлениями. В локалке их, правда, все равно - создается
    // по два - тк пакеты идут с обоих машин.

   i=1;                      //  SRC -> DEST
   if (pack[0] != 0x20) i=2; // DEST -> SRC

   wsprintf(b1,"%s",inet_ntoa(ia[i]));             // dirname
   wsprintf(b1,"%s-%s",b1,inet_ntoa(ia[3-i]));

   wsprintf(b2,"%i-%i",p[i],p[3-i]);               // port

   wsprintf(b3,"\n\n%s:%u",inet_ntoa(ia[1]),p[1]); // direction
   wsprintf(b3,"%s -> %s:%u\n\n",b3,inet_ntoa(ia[2]),p[2]);

   char fn[700];                                   // save
   CreateDirectory(b1,NULL);
   wsprintf(fn,"%s\\%s",b1,b2);
   hndl=CreateFile(fn,GENERIC_WRITE,0,NULL,OPEN_ALWAYS, \
                   FILE_ATTRIBUTE_NORMAL,NULL);
   SetFilePointer(hndl,0,0,FILE_END);
   WriteFile(hndl,b3,strlen(b3),&i,NULL);
   WriteFile(hndl,data,tlen-54,&i,NULL);
   CloseHandle(hndl);
  }

  off = Packet_WORDALIGN(off+tlen); // едем дальше
 }
}

/*- Entry Point -*/

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance, \
                   char *szCmdLine,int iCmdShow)
{
  // получаем адаптеры
 AdapterLength=512; i=0;

 LPOSVERSIONINFO osver;
 GetVersionEx(osver);

 if (osver->dwPlatformId == VER_PLATFORM_WIN32_NT)
 {  // для Windows NT
  PacketGetAdapterNames(AdapterName,&AdapterLength);
  temp=AdapterName; temp1=AdapterName;

  while ((*temp!='\0')||(*(temp-1)!='\0'))
  {
   if (*temp=='\0')
   {
    memcpy(AdapterList[i],temp1,(temp-temp1)*2);
    temp1=temp+1;
    i++;
   }
   temp++;
  }

  AdapterNum=i;
  for (i=0;ihFile == INVALID_HANDLE_VALUE)) exit(1);

  // ставим адаптер в promiscuous mode
 PacketSetHwFilter(lpAdapter,NDIS_PACKET_TYPE_PROMISCUOUS);

  // определяем размер буфера для драйвера
 PacketSetBuff(lpAdapter,512000);

  // 1000 ms таймаут на чтение
 PacketSetReadTimeout(lpAdapter,1000);

  // инициализируем структуру для приема пакетов
  // в случае облома - выход
 if ((lpPacket = PacketAllocatePacket()) == NULL) exit(1);
 PacketInitPacket(lpPacket,(char*)buffer,sizeof(buffer));

  // далее регаем класс и создаем окошко - win32 все-таки
 static char szAppName[] = " ";
 MSG msg;
 WNDCLASS wndclass;

 wndclass.style         = CS_HREDRAW|CS_VREDRAW;
 wndclass.lpfnWndProc   = WndProc;
 wndclass.cbClsExtra    = 0;
 wndclass.cbWndExtra    = 0;
 wndclass.hInstance     = hInstance;
 wndclass.hIcon         = NULL;
 wndclass.hCursor       = NULL;
 wndclass.hbrBackground = NULL;
 wndclass.lpszMenuName  = NULL;
 wndclass.lpszClassName = szAppName;

 RegisterClass(&wndclass);
 hwnd = CreateWindow(szAppName,"",WS_OVERLAPPEDWINDOW,0,0,0,0,NULL, \
                     NULL,hInstance,NULL);

 SetTimer(hwnd,1,1000,0); // вешаем чтение на таймер

 while (GetMessage(&msg,NULL,0,0))
 {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }

 return msg.wParam ;
}

/*- Обработка событий -*/

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, \
                         WPARAM wParam, LPARAM lParam)
{
 switch (iMsg)
 {
  case WM_TIMER: // читаем пакеты и отправляем их хм... на разборку
   PacketReceivePacket(lpAdapter,lpPacket,TRUE);
   packets(lpPacket);
  break;
 }
}

  После  компиляции,  вы  получите  6  (lcc-win32)  или 15 кб (VC) нечта,
 которое   при   запуске  без  параметров  формирует  список  адаптеров в
 adapters.txt,  а  при  указании  собственно  имени  адаптера  в качестве
 первого  параметра,  начинается сниффинг TCP пакетов. Если вам требуется
 отловить нечто другое - просто убейте if.

  Большая  просьба  протестировать все это дело под NT/2k/XP. Поскольку я
 на 100% ручаюсь только за работу под 9x - под ними и гонял.

  Уфф...  ну  вроде  все.  Если  кто  баги  найдет какие, или предложения
 возникнут,   или   вообще  деньги  лишние  завалялись  ;)  -  пишите  на
 [email protected]. Удачи!