可以从Windows Sockets 2开始,
虽然微软提供了官方工具, Microsoft Network Monitor 3.4, 不过我们如果能够通过相关的代码和api的调用来深入研究的话,那就大大提升了我们的学习水平。
主要用到socket, bind 和 recvfrom函数。
代码样本:
#include "stdio.h" #include "winsock2.h" #pragma comment(lib,"ws2_32.lib") //For winsock #pragma warning(disable:4996) #define SIO_RCVALL _WSAIOW(IOC_VENDOR,1) //this removes the need of mstcpip.h void StartSniffing(SOCKET Sock); //This will sniff here and there void ProcessPacket(char*, int); //This will decide how to digest void PrintIpHeader(char*); void PrintUdpPacket(char*, int); void PrintTcpPacket(char*, int); void PrintData(char*, int); typedef struct ip_hdr { unsigned char ip_header_len : 4; // 4-bit header length (in 32-bit words) normally=5 (Means 20 Bytes may be 24 also) unsigned char ip_version : 4; // 4-bit IPv4 version unsigned char ip_tos; // IP type of service unsigned short ip_total_length; // Total length unsigned short ip_id; // Unique identifier unsigned char ip_frag_offset : 5; // Fragment offset field unsigned char ip_more_fragment : 1; unsigned char ip_dont_fragment : 1; unsigned char ip_reserved_zero : 1; unsigned char ip_frag_offset1; //fragment offset unsigned char ip_ttl; // Time to live unsigned char ip_protocol; // Protocol(TCP,UDP etc) unsigned short ip_checksum; // IP checksum unsigned int ip_srcaddr; // Source address unsigned int ip_destaddr; // Source address } IPV4_HDR; typedef struct udp_hdr { unsigned short source_port; // Source port no. unsigned short dest_port; // Dest. port no. unsigned short udp_length; // Udp packet length unsigned short udp_checksum; // Udp checksum (optional) } UDP_HDR; // TCP header typedef struct tcp_header { unsigned short source_port; // source port unsigned short dest_port; // destination port unsigned int sequence; // sequence number - 32 bits unsigned int acknowledge; // acknowledgement number - 32 bits unsigned char ns : 1; //Nonce Sum Flag Added in RFC 3540. unsigned char reserved_part1 : 3; //according to rfc unsigned char data_offset : 4; /*The number of 32-bit words in the TCP header. This indicates where the data begins. The length of the TCP header is always a multiple of 32 bits.*/ unsigned char fin : 1; //Finish Flag unsigned char syn : 1; //Synchronise Flag unsigned char rst : 1; //Reset Flag unsigned char psh : 1; //Push Flag unsigned char ack : 1; //Acknowledgement Flag unsigned char urg : 1; //Urgent Flag unsigned char ecn : 1; //ECN-Echo Flag unsigned char cwr : 1; //Congestion Window Reduced Flag //////////////////////////////// unsigned short window; // window unsigned short checksum; // checksum unsigned short urgent_pointer; // urgent pointer } TCP_HDR; FILE* logfile; int tcp = 0, udp = 0, icmp = 0, others = 0, igmp = 0, total = 0, i, j; struct sockaddr_in source, dest; char hex[2]; //Its free! IPV4_HDR* iphdr; TCP_HDR* tcpheader; UDP_HDR* udpheader; int main() { SOCKET sniffer; struct in_addr addr; int in; char hostname[100]; struct hostent* local; WSADATA wsa; logfile = fopen("log.txt", "w"); if (logfile == NULL) { printf("Unable to create file."); } //Initialise Winsock printf(" Initialising Winsock..."); if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) { printf("WSAStartup() failed. "); return 1; } printf("Initialised"); //Create a RAW Socket printf(" Creating RAW Socket..."); sniffer = socket(AF_INET, SOCK_RAW, IPPROTO_IP); if (sniffer == INVALID_SOCKET) { printf("Failed to create raw socket. "); return 1; } printf("Created."); //Retrive the local hostname if (gethostname(hostname, sizeof(hostname)) == SOCKET_ERROR) { printf("Error : %d", WSAGetLastError()); return 1; } printf(" Host name : %s ", hostname); //Retrive the available IPs of the local host local = gethostbyname(hostname); printf(" Available Network Interfaces : "); if (local == NULL) { printf("Error : %d. ", WSAGetLastError()); return 1; } for (i = 0; local->h_addr_list[i] != 0; ++i) { memcpy(&addr, local->h_addr_list[i], sizeof(struct in_addr)); printf("Interface Number : %d Address : %s ", i, inet_ntoa(addr)); } printf("Enter the interface number you would like to sniff : "); scanf("%d", &in); memset(&dest, 0, sizeof(dest)); memcpy(&dest.sin_addr.s_addr, local->h_addr_list[in], sizeof(dest.sin_addr.s_addr)); dest.sin_family = AF_INET; dest.sin_port = 0; printf(" Binding socket to local system and port 0 ..."); if (bind(sniffer, (struct sockaddr*) & dest, sizeof(dest)) == SOCKET_ERROR) { printf("bind(%s) failed. ", inet_ntoa(addr)); return 1; } printf("Binding successful"); //Enable this socket with the power to sniff : SIO_RCVALL is the key Receive ALL ;) j = 1; printf(" Setting socket to sniff..."); if (WSAIoctl(sniffer, SIO_RCVALL, &j, sizeof(j), 0, 0, (LPDWORD)&in, 0, 0) == SOCKET_ERROR) { printf("WSAIoctl() failed. "); return 1; } printf("Socket set."); //Begin printf(" Started Sniffing "); printf("Packet Capture Statistics... "); StartSniffing(sniffer); //Happy Sniffing //End closesocket(sniffer); WSACleanup(); return 0; } void StartSniffing(SOCKET sniffer) { char* Buffer = (char*)malloc(65536); //Its Big! int mangobyte; if (Buffer == NULL) { printf("malloc() failed. "); return; } do { mangobyte = recvfrom(sniffer, Buffer, 65536, 0, 0, 0); //Eat as much as u can if (mangobyte > 0) { ProcessPacket(Buffer, mangobyte); } else { printf("recvfrom() failed. "); } } while (mangobyte > 0); free(Buffer); } void ProcessPacket(char* Buffer, int Size) { iphdr = (IPV4_HDR*)Buffer; ++total; switch (iphdr->ip_protocol) //Check the Protocol and do accordingly... { case 6: //TCP Protocol ++tcp; PrintTcpPacket(Buffer, Size); break; case 17: //UDP Protocol ++udp; PrintUdpPacket(Buffer, Size); break; default: //Some Other Protocol like ARP etc. ++others; break; } printf("TCP : %d UDP : %d ICMP : %d IGMP : %d Others : %d Total : %d ", tcp, udp, icmp, igmp, others, total); } void PrintIpHeader(char* Buffer) { unsigned short iphdrlen; iphdr = (IPV4_HDR*)Buffer; iphdrlen = iphdr->ip_header_len * 4; memset(&source, 0, sizeof(source)); source.sin_addr.s_addr = iphdr->ip_srcaddr; memset(&dest, 0, sizeof(dest)); dest.sin_addr.s_addr = iphdr->ip_destaddr; fprintf(logfile, " "); fprintf(logfile, "IP Header "); fprintf(logfile, " |-IP Version : %d ", (unsigned int)iphdr->ip_version); fprintf(logfile, " |-IP Header Length : %d DWORDS or %d Bytes ", (unsigned int)iphdr->ip_header_len, ((unsigned int)(iphdr->ip_header_len)) * 4); fprintf(logfile, " |-Type Of Service : %d ", (unsigned int)iphdr->ip_tos); fprintf(logfile, " |-IP Total Length : %d Bytes(Size of Packet) ", ntohs(iphdr->ip_total_length)); fprintf(logfile, " |-Identification : %d ", ntohs(iphdr->ip_id)); fprintf(logfile, " |-Reserved ZERO Field : %d ", (unsigned int)iphdr->ip_reserved_zero); fprintf(logfile, " |-Dont Fragment Field : %d ", (unsigned int)iphdr->ip_dont_fragment); fprintf(logfile, " |-More Fragment Field : %d ", (unsigned int)iphdr->ip_more_fragment); fprintf(logfile, " |-TTL : %d ", (unsigned int)iphdr->ip_ttl); fprintf(logfile, " |-Protocol : %d ", (unsigned int)iphdr->ip_protocol); fprintf(logfile, " |-Checksum : %d ", ntohs(iphdr->ip_checksum)); fprintf(logfile, " |-Source IP : %s ", inet_ntoa(source.sin_addr)); fprintf(logfile, " |-Destination IP : %s ", inet_ntoa(dest.sin_addr)); } void PrintTcpPacket(char* Buffer, int Size) { unsigned short iphdrlen; iphdr = (IPV4_HDR*)Buffer; iphdrlen = iphdr->ip_header_len * 4; tcpheader = (TCP_HDR*)(Buffer + iphdrlen); fprintf(logfile, " ***********************TCP Packet************************* "); PrintIpHeader(Buffer); fprintf(logfile, " "); fprintf(logfile, "TCP Header "); fprintf(logfile, " |-Source Port : %u ", ntohs(tcpheader->source_port)); fprintf(logfile, " |-Destination Port : %u ", ntohs(tcpheader->dest_port)); fprintf(logfile, " |-Sequence Number : %u ", ntohl(tcpheader->sequence)); fprintf(logfile, " |-Acknowledge Number : %u ", ntohl(tcpheader->acknowledge)); fprintf(logfile, " |-Header Length : %d DWORDS or %d BYTES " , (unsigned int)tcpheader->data_offset, (unsigned int)tcpheader->data_offset * 4); fprintf(logfile, " |-CWR Flag : %d ", (unsigned int)tcpheader->cwr); fprintf(logfile, " |-ECN Flag : %d ", (unsigned int)tcpheader->ecn); fprintf(logfile, " |-Urgent Flag : %d ", (unsigned int)tcpheader->urg); fprintf(logfile, " |-Acknowledgement Flag : %d ", (unsigned int)tcpheader->ack); fprintf(logfile, " |-Push Flag : %d ", (unsigned int)tcpheader->psh); fprintf(logfile, " |-Reset Flag : %d ", (unsigned int)tcpheader->rst); fprintf(logfile, " |-Synchronise Flag : %d ", (unsigned int)tcpheader->syn); fprintf(logfile, " |-Finish Flag : %d ", (unsigned int)tcpheader->fin); fprintf(logfile, " |-Window : %d ", ntohs(tcpheader->window)); fprintf(logfile, " |-Checksum : %d ", ntohs(tcpheader->checksum)); fprintf(logfile, " |-Urgent Pointer : %d ", tcpheader->urgent_pointer); fprintf(logfile, " "); fprintf(logfile, " DATA Dump "); fprintf(logfile, " "); fprintf(logfile, "IP Header "); PrintData(Buffer, iphdrlen); fprintf(logfile, "TCP Header "); PrintData(Buffer + iphdrlen, tcpheader->data_offset * 4); fprintf(logfile, "Data Payload "); PrintData(Buffer + iphdrlen + tcpheader->data_offset * 4 , (Size - tcpheader->data_offset * 4 - iphdr->ip_header_len * 4)); fprintf(logfile, " ###########################################################"); } void PrintUdpPacket(char* Buffer, int Size) { unsigned short iphdrlen; iphdr = (IPV4_HDR*)Buffer; iphdrlen = iphdr->ip_header_len * 4; udpheader = (UDP_HDR*)(Buffer + iphdrlen); fprintf(logfile, " ***********************UDP Packet************************* "); PrintIpHeader(Buffer); fprintf(logfile, " UDP Header "); fprintf(logfile, " |-Source Port : %d ", ntohs(udpheader->source_port)); fprintf(logfile, " |-Destination Port : %d ", ntohs(udpheader->dest_port)); fprintf(logfile, " |-UDP Length : %d ", ntohs(udpheader->udp_length)); fprintf(logfile, " |-UDP Checksum : %d ", ntohs(udpheader->udp_checksum)); fprintf(logfile, " "); fprintf(logfile, "IP Header "); PrintData(Buffer, iphdrlen); fprintf(logfile, "UDP Header "); PrintData(Buffer + iphdrlen, sizeof(UDP_HDR)); fprintf(logfile, "Data Payload "); PrintData(Buffer + iphdrlen + sizeof(UDP_HDR), (Size - sizeof(UDP_HDR) - iphdr->ip_header_len * 4)); fprintf(logfile, " ###########################################################"); } /* Print the hex values of the data */ void PrintData(char* data, int Size) { char a, line[17], c; int j; //loop over each character and print for (i = 0; i < Size; i++) { c = data[i]; //Print the hex value for every character , with a space. Important to make unsigned fprintf(logfile, " %.2x", (unsigned char)c); //Add the character to data line. Important to make unsigned a = (c >= 32 && c <= 128) ? (unsigned char)c : '.'; line[i % 16] = a; //if last character of a line , then print the line - 16 characters in 1 line if ((i != 0 && (i + 1) % 16 == 0) || i == Size - 1) { line[i % 16 + 1] = '