Побег через брандмаузер

         

создание сырого сокета (дескриптора) и перевод его в неразборчивый режим


Совсем иная ситуация складывается с  Windows NT. Пакетных сокетов она не поддерживает, с сетевым драйвером напрямую работать не позволяет. Точнее позволяет, но с очень большими предосторожностями и не без плясок с бубном (если нет бубна, на худой конец сойдет и обыкновенный оцинкованный таз, подробное изложение ритуала можно найти у Коберниченко в "Недокументированных возможностях Windows NT"). И хотя пакетных снифферов под NT существует огромное количество (один из которых даже входит в DDK), все они требуют обязательной установки специального драйвера, т. к. корректная работа с транспортом в NT возможна только на уровне ядра. Может ли червь притащить с собой такой драйвер и динамически загрузить его в систему? Ну, вообще-то может, только это будет крайне громоздкое и неэлегантное решение.

В Windows 2000/XP все гораздо проще. Там достаточно создать сырой сокет (в Windows 2000/XP наконец-то появилась поддержка сырых сокетов!), повестить его на прослушиваемый интерфейс и, сделав сокету bind, перевести последний в неразборчивый режим, сказав WSAIoctl(raw_socket, SIO_RCVALL, &optval, sizeof(optval), 0,0,&N,0,0)), где optval – переменная типа DWORD с единицей внутри, а N – количество возращенных функцией байт.

Впервые исходный текст такого сниффера был опубликован в шестом номере журнала #29A, затем его передрал Z0mnie, переложивший ассемблерный код на интернациональный программистский язык Си++ (странно, а почему не Си?) и унаследовавший все ляпы оригинала. Ниже приведен его ключевой фрагмент с моими комментариями, а полный исходный текст содержится в файле sniffer.с. Другой источник вдохновления – демонстрационный пример IPHDRINC, входящий в состав Platform SDK 2000. Рекомендую.

// создаем сырой сокет

//------------------------------------------------------------------------

if ((raw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IP)) == -1) return -1;

// вот тут некоторые руководства утверждают, что сырому сокету надо дать


// атрибут IP_HDRINCL. дать-то, конечно, можно, но ведь можно и не давать!

// флаг IP_HDRINCL сообщает системе, что аплеуха хочет сама формировать

// IP заголовок отправляемых пакетов, а принятые пакеты ей отдаются с IP

// заголовком в любом случае. подробности в PlatformSDK->
TCP/IP Raw Sockets

//if (setsockopt(raw_socket, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(optval))== -1)…

// перечисляем все интерфейсы (т.е. адреса IP-адресов всех шлюзов, что

// есть на компьютере. при ppp-подлюкчении к инетернет обычно имеется

// всего один IP-адрес, назначенный DHCP сервером провайдера, однако,



// в локальной сети это не так

if ((zzz = WSAIoctl(raw_socket, SIO_ADDRESS_LIST_QUERY, 0, 0, addrlist,

        sizeof(addrlist), &N, 0, 0)) == SOCKET_ERROR) return -1;



// теперь мы должны сделать bind на все интерфейсы, выделив каждый в свой

// поток (весь сокеты - блокируемые), однако, в данном демонстрационном

// примере слушается лишь IP первого попавшегося под руку интерфейса

addr.sin_family = AF_INET;

addr.sin_addr   = ((struct sockaddr_in*) llist->
Address[0].lpSockaddr)->
sin_addr;

if (bind(raw_socket, (struct sockaddr*) &addr, sizeof(addr))==SOCKET_ERROR) return -1;

#define SIO_RCVALL  0x98000001

// сообщаем системе, что мы хотим получать все пакеты, проходящие мимо нее

if (zzz=WSAIoctl(raw_socket,SIO_RCVALL,&optval,sizeof(optval),0,0,&N,0,0)) return –1;

// получаем все пакеты, приходящие на данный интерфейс

while(1)

{

       if ((len = recv(raw_socket, buf, sizeof(buf), 0)) < 1) return -1;

       …

}


Содержание раздела