Смысл тут в чем, icmp достаточно прост, в него можно зашифровать достаточно много данных и он особа не привлекает внимание. Например некоторые даже поднимают целый тунель только на icmp чтобы обойти фаерволы и злобных админов.
Программа достаточно проста, в ней нет никакого шифрования, она не ведет лог, но позволяет обмениваться сообщениями в локальной сети. Программу достаточно легко переделать в универсальный снифер для любых пакетов, заменив пару параметров и сделав обертку в виде разбора пакетов. И все это всего в нескольких не оптимизированных килобайтах, мой проект например получился ровно 4кб.
А теперь собственно основные части программы:
Инициализация:
init_ws proc ; инициируем винсок и прочее invoke gethostname, offset compname, sizeof compname ; получаем адрес на структуру с именем и ип адресом invoke WSAStartup, WSVERSION, offset ws ; инициируем винсок invoke socket, AF_INET, SOCK_RAW, IPPROTO_ICMP ; открываем сокет на отправку mov sock, eax ; копируем сокет в переменную ret init_ws endp
Процедура отправки сообщения:
sendmsg proc ; процедура отправки сообщения invoke inet_addr, offset addr_ip ; переводим ип адрес получателя в hex mov saddr.sin_addr,eax ; заносим уго в структуру sockaddr_in invoke htons, PORT_ADDR ; переводим порт в hex mov saddr.sin_port,ax ; и его в структуру sockaddr_in mov saddr.sin_family,AF_INET ; заносим тип сети в структуру sockaddr_in invoke setsockopt, sock, SOL_SOCKET, SO_RCVTIMEO, optval, sizeof optval ; устанавливаем параметры mov packet.typ, 8h ; создаем icmp request пакет mov packet.chksum, 0h ; чексумма при создании должна быть 0 mov packet.ident, 6863h ; 6863h - id пакета invoke lstrcpy, offset packet.dat, offset textstr ; копируем строчку в созданный пакет invoke icmpchecksum, offset packet, sizeof packet ; считаем получившуюся чексумму mov packet.chksum, ax ; заносим чексуму в соотвествующее поле invoke sendto, sock, offset packet, sizeof packet, 0, offset saddr, sizeof saddr ; отправляем пакет ret sendmsg endp
Для того чтобы пакет был валидный, надо посчитать его чек сумму, хотя конечно можно и забить, но такой пакет могут не пропустить через себя маршрутизаторы, так что будем делать по правилам.
Процедурка подсчета чек суммы:
icmpchecksum proc icmppacket:DWORD, psize:DWORD ; процедурка подсчета чек суммы mov edi, icmppacket ; в edi указатель на начало пакета mov ax, WORD PTR [edi] ; в ax первые 2 байта из пакета xchg al, ah ; поменять местами mov ecx, 2h ; увеличить счетчик на 2 nextword: mov bx, WORD PTR [edi+ecx] ; в bx поместить следующие 2 байта xchg bl, bh ; их тоже поменять местами add ax, bx ; сложить ax + bx jnc noverflow ; если нет переполнения прыгнуть на noverflow inc ax ; иначе увеличить ax на 1 noverflow: add ecx, 2h ; прибавить к счетчику 2 .if ecx >= psize ; сравнить, превысили или равно колчество байт jmp endchk ; если превысили/равно - прыгнуть на выход из функции .endif jmp nextword ; повторить со следующими 2мя байтами endchk: not ax ; инвертировать биты xchg al, ah ; снова поменять местами ret icmpchecksum endp
И наконец, процедурка приема сообщений, которая к стати без проблем переделывается в простой снифер, без написания всяких дров и использования библ pcap:
recvmsg proc hWin:DWORD ; процедурка приема сообщений LOCAL sock2:DWORD ; локальная переменная для второй копии сокета mov rflag, 1 ; флаг для треда invoke socket, AF_INET, SOCK_RAW, IPPROTO_ICMP ; откроем сокет mov sock2, eax ; закопируем в переменную invoke gethostbyname, offset compname ; получим ссылку на структуру со совим ип адресом mov eax, DWORD PTR [eax+1Ch] ; теперь сам ип адрес mov inaddr.sin_addr,eax ; копируем ip адрес в структуру sockaddr_in mov inaddr.sin_family,AF_INET ; копируем тип сети в структуру sockaddr_in invoke bind, sock2, offset inaddr, sizeof inaddr ; биндим сокет mov lsaddr, sizeof inaddr ; получаем размер структуры lsaddr mov sflag, TRUE ; поставим флаг в TRUE invoke ioctlsocket, sock2, SIO_RCVALL,offset sflag ; переведем сокет в режим прослушивания nextpacket: invoke recvfrom,sock2, offset buf, sizeof buf, 0, ADDR inaddr, ADDR lsaddr ; ждем пакет mov eax, DWORD PTR [buf+0Ch] ; копируем ип адрес пришедшего пакета .if saddr.sin_addr != eax ; не совпадает с ип адресом абонента jmp fchk ; прыгаем на fchk .endif mov al, BYTE PTR [buf+14h] ; копируем тип .if al != 8h ; если не icmp request jmp fchk ; прыгаем на выход .endif mov ax, WORD PTR [buf+18h] ; копируем идентификатор .if ax != 6863h ; если пакет не из нашей программы jmp fchk ; прыгаем на выход .endif lea eax, DWORD PTR [buf+1ch] ; получаем ссылку на тело сообщения invoke PostMessage, hWin, WM_FINISH,NULL, NULL ; сигнализируем основной программе, что получили валидный пакет fchk: jmp nextpacket ; ждем следующего пакета ret recvmsg endp
А теперь код целиком для ручной сборки: http://pastebin.com/QVRuLnMm
Ну или готовый проект с откомпилированным исходником: http://depositfiles.com/files/wp692b99a
Комментариев нет:
Отправить комментарий