1. 程式人生 > >使用 網絡卡混雜模式 編寫網路抓包程式

使用 網絡卡混雜模式 編寫網路抓包程式

都說在winsock2中支援抓包功能了,在網上找了個例子,修改一下,在windows xp + VC2003 下測試通過。不知道能不能做成QQ訊息嗅探工具,試驗中


 
#pragma comment(lib,"ws2_32.lib")        // sokect 2

# include "winsock2.h"
# include "ws2tcpip.h"
# include<stdio.h>
#include <mstcpip.h>

typedef struct _TCP
{
 WORD SrcPort; // 源埠  
 WORD DstPort; // 目的埠
 DWORD SeqNum; // 順序號
 DWORD AckNum; // 確認號
 BYTE DataOff; // TCP頭長
 BYTE Flags; // 標誌(URG、ACK等)
 WORD Window; // 視窗大小
 WORD Chksum; // 校驗和
 WORD UrgPtr; // 緊急指標
} TCP;
typedef TCP *LPTCP;
typedef TCP UNALIGNED * ULPTCP;

typedef struct _UDP
{
 unsigned short SrcPort ; //WORD SrcPort; // 源埠
 unsigned short DstPort ; //WORD DstPort; // 目的埠
 short Length;            //WORD Length; // UDP 長度
 unsigned short Chksum;   //WORD Chksum; // 校驗和
} UDP;
typedef UDP *LPUDP;
typedef UDP UNALIGNED * ULPUDP;


typedef struct _IP
{
 union{ BYTE Version; // 版本        //     |前4位 是 版本號| 後4位 是頭的長度|
 BYTE HdrLen; // IHL                 //其中,頭的第一個欄位指定的是IP版本,目前通常是版本4。頭長度是指在整個頭中, 3 2
                                        // 位字一共有多少個(一頭的長度必須是3 2位的整數倍)
 };
 BYTE ServiceType; // 服務型別
 WORD TotalLen; // 總長
 WORD ID; // 標識
 union{ WORD Flags; // 標誌
 WORD FragOff; // 分段偏移
 };
 BYTE TimeToLive; // 生命期
 BYTE Protocol; // 協議
 WORD HdrChksum; // 頭校驗和
 DWORD SrcAddr; // 源地址
 DWORD DstAddr; // 目的地址
 BYTE Options[0]; // 選項
 // 根據Network Programming for Microsoft Windows 1st 的描述
 //IP選項欄位是一個長度不定的欄位,包含了某些可選的資訊,通常與I P安全或路由選擇有關
 //但書中,沒有說如何確定這個長度,有的書上定一個結構也是沒有這個結構的,所以這裡也註釋掉了,才能獲得
 //正確的埠號。

} IP; 
typedef IP * LPIP;
typedef IP UNALIGNED * ULPIP;


char * GetProtocolTxt(int Protocol)
{
 switch (Protocol){
case IPPROTO_ICMP : //1 
 return "ICMP";
case IPPROTO_TCP : //6  
 return "TCP";
case IPPROTO_UDP : //17   
 return "UDP";
default:
 return "unknown";
 }

}


int main()
{
 
 sockaddr_in addr_in;
 const int  BUFFER_SIZE =65535;
 int  flag =1;
 char LocalName[256];
 hostent  * pHost;
 char RecvBuf [BUFFER_SIZE];
 SOCKET sock;
 IP ip;
 TCP tcp;
 WSADATA WSAData;


 printf("haha\n");

 if (0  != WSAStartup(MAKEWORD(2, 2), &WSAData))   
 {
  printf("WSAStartup fail to initialize !\n");
 }
 // 建立原始套接字 ////////這裡最後一個選項必須時IPPROTO_IP才能收到網路包
 //原來為sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);,結果收不到網路包。
 sock = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
    if (sock == INVALID_SOCKET )
 {
  printf("socket create fail !\n");
 }

 
     // 設定IP頭操作選項,其中flag 設定為true,親自對IP頭進行處理
 

 // 設定IP頭操作選項,其中flag 設定為true,親自對IP頭進行處理
    //原來宣告 bool flag=true,執行不成功,改為 int  flag =1;
 if ( 0 != setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char*)&flag, sizeof(flag)))
 {
  printf("setsockopt fail  ! \n");
 }
 

 // 獲取本機名
 if (0 !=gethostname((char*)LocalName, sizeof(LocalName)-1))
 {   
  printf("gethostname  fail  ! \n");
 }
 else 
 {
  printf("hostname=%s \n",LocalName);
 }

 // 獲取本地 IP 地址
 pHost = gethostbyname((char*)LocalName);
 if  (pHost==NULL)
 {
   printf("gethostbyname  fail  ! \n");
 }


 // 填充SOCKADDR_IN結構
 addr_in.sin_addr = *(in_addr *)pHost->h_addr_list[0]; //IP
 addr_in.sin_family = AF_INET;
 addr_in.sin_port = htons(45882);


 // 把原始套接字sock 繫結到本地網絡卡地址上
 if( 0!=bind(sock, (PSOCKADDR)&addr_in, sizeof(addr_in)))
 {
 printf("bind failed ! \n");
 }

 // dwValue為輸入輸出引數,為1時執行,0時取消
 DWORD dwValue = 1; 
 // 設定 SOCK_RAW 為SIO_RCVALL,以便接收所有的IP包。其中SIO_RCVALL
 // 的定義為: #define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)
 if ( 0 != ioctlsocket(sock, SIO_RCVALL, &dwValue))
 {
  printf("ioctlsocket failed !\n");
 }


 
 while (true)
 {
  

  //If no incoming data is available at the socket, the recv call blocks and waits for data to arrive according to the blocking rules defined for WSARecv with the MSG_PARTIAL flag not set unless the socket is nonblocking. In this case, a value of SOCKET_ERROR is returned with the error code set to WSAEWOULDBLOCK. The select, WSAAsyncSelect, or WSAEventSelect functions can be used to determine when more data arrives
  // 接收原始資料包資訊
  int ret = recv(sock, RecvBuf, BUFFER_SIZE, 0);

  if (ret > 0)
  {


   printf("%s",RecvBuf);
   // 對資料包進行分析,並輸出分析結果
   ip = *(IP*)RecvBuf;
   tcp = *(TCP*)(RecvBuf + 4 *(ip.HdrLen  & 0xF)); //ip.HdrLen  & 0xF 得到IP頭長度,這個長度是32位字的個數
      printf("協議: %s\r\n",GetProtocolTxt(ip.Protocol));
   printf("IP源地址: %s\r\n",inet_ntoa(*(in_addr*)&ip.SrcAddr));
   printf("IP目標地址: %s\r\n",inet_ntoa(*(in_addr*)&ip.DstAddr));
   printf("TCP源埠號: %d\r\n", ntohs (tcp.SrcPort));  //需要ntohs()轉換才能得到正常所要的埠號
   //The ntohs function converts a u_short from TCP/IP network byte order to host byte order (which is little-endian on Intel processors).
   printf("TCP目標埠號:%d\r\n", ntohs (tcp.DstPort));
   printf("資料包長度: %d\r\n\r\n\r\n",ntohs(ip.TotalLen));
            
  }
  else if (ret == 0)
  {
   printf ("the connection has been gracefully closed\r\n");
  }
 }

}

以下資料來自 MSDN

===============================

TCP/IP Raw Sockets

The TCP/IP service providers may support the SOCK_RAW socket type. There are two types of such sockets:

  • The first type assumes a known protocol type as written in the IP header. An example of the first type of socket is ICMP.
  • The second type allows any protocol number. An example of the second type would be an experimental protocol that is not supported by the service provider.

If a TCP/IP service provider supports SOCK_RAW sockets for the AF_INET family, the corresponding protocol(s) should be included in the list returned by WSAEnumProtocols. The iProtocol member of the WSAPROTOCOL_INFO structure may be set to zero if the service provider allows an application to specify any value for the protocol parameter for the SocketWSASocket, and WSPSocket functions.

Note  An application may not specify zero (0) as the protocol parameter for the SocketWSASocket, and WSPSocket functions if SOCK_RAW sockets are used.

The following rules are applied to the operations over SOCK_RAW sockets:

  • When an application sends a datagram it may or may not include the IP header at the front of the outgoing datagrams depending on the IP_HDRINCL option set for the socket.
  • An application always gets the IP header at the front of each received datagram regardless of the IP_HDRINCL option.
  • Received datagrams are copied into all SOCK_RAW sockets that satisfy the following conditions:

    • The protocol number specified for the socket should match the protocol number in the IP header of the received datagram.
    • If a local IP address is defined for the socket, it should correspond to the destination address as specified in the IP header of the received datagram. An application may specify the local IP address by calling bind functions. If no local IP address is specified for the socket, the datagrams are copied into the socket regardless of the destination IP address in the IP header of the received datagram.
    • If a foreign address is defined for the socket, it should correspond to the source address as specified in the IP header of the received datagram. An application may specify the foreign IP address by calling connect functions. If no foreign IP address is specified for the socket, the datagrams are copied into the socket regardless of the source IP address in the IP header of the received datagram.

It is important to understand that SOCK_RAW sockets may get many unexpected datagrams. For example, a PING program may use SOCK_RAW sockets to send ICMP echo requests. While the application is expecting ICMP echo responses, all other ICMP messages (such as ICMP HOST_UNREACHABLE) may be delivered to this application also. Moreover, if several SOCK_RAW sockets are open on a machine at the same time, the same datagrams may be delivered to all the open sockets. An application must have a mechanism to recognize its datagram and to ignore all others. Such mechanism may include inspecting the received IP header???using unique identifiers in the ICMP header (ProcessID, for example), and so forth.

Note  Raw socket support requires administrative privileges. Users running Winsock applications that make use of raw sockets must have administrative privileges on the computer, otherwise raw socket calls will fail with an error code of WSAEACCES.

Note  The Microsoft implementation of TCP/IP on Windows is capable of opening a raw UDP socket.

=============================================

AF_INET

[This is preliminary documentation and subject to change.]

The AF_INET address family is the address family for IPv4.

Socket Address Structure

An IPv4 transport address is specified with the SOCKADDR_IN structure.

Socket Types

IPv4 supports the following socket types:

SOCK_STREAM
Supports reliable connection-oriented byte stream communication.
SOCK_DGRAM
Supports unreliable connectionless datagram communication.
SOCK_RAW
Supports raw access to the transport protocol.

A WSK application specifies a socket type when it calls the WskSocket function or the WskSocketConnect function to create a new socket.

Protocols

The following IPv4 IPPROTO_XXX protocol values are defined in the WSK header files:

IPPROTO_IP
Internet protocol options
IPPROTO_ICMP
Internet control message protocol
IPPROTO_IGMP
Internet group management protocol
IPPROTO_GGP
Gateway to gateway protocol
IPPROTO_IPV4
IPv4 encapsulation
IPPROTO_ST
Stream protocol
IPPROTO_TCP
Transmission control protocol
IPPROTO_CBT
Core based trees protocol
IPPROTO_EGP
Exterior gateway protocol
IPPROTO_IGP
Private interior gateway protocol
IPPROTO_PUP
PARC universal packet protocol
IPPROTO_UDP
User datagram protocol
IPPROTO_IDP
Internet datagram protocol
IPPROTO_RDP
Reliable data protocol
IPPROTO_ND
Net disk protocol
IPPROTO_ICLFXBM
Wideband monitoring
IPPROTO_PIM
Protocol independent multicast
IPPROTO_PGM
Pragmatic general multicast
IPPROTO_L2TP
Level 2 tunneling protocol
IPPROTO_SCTP
Stream control transmission protocol
IPPROTO_RAW
Raw IP packets

Additional protocols are supported through the use of raw sockets.

A WSK application specifies a protocol when it calls the WskSocket function or the WskSocketConnect function to create a new socket.

A WSK application also specifies a protocol (as the Level parameter) when it calls the WskControlSocket function to set or retrieve transport protocol level or network protocol level socket options.

Combinations

IPv4 supports the following combinations of socket types and protocols for each WSK socket category:

Basic Sockets
SOCK_STREAM + IPPROTO_TCP
SOCK_DGRAM + IPPROTO_UDP
SOCK_RAW + IPPROTO_XXX
Listening Sockets
SOCK_STREAM + IPPROTO_TCP
Datagram Sockets
SOCK_DGRAM + IPPROTO_UDP
SOCK_RAW + IPPROTO_XXX
Connection-Oriented Sockets
SOCK_STREAM + IPPROTO_TCP