zoukankan      html  css  js  c++  java
  • 实践三 网络嗅探与协议分析

    一、

    根据教材参考代码,编写有个简单网络抓包工具。要求核心代码和运行结果截图1-2张。


    • 首先再再再次感谢启龙同学,这次作业或许对于有基础的人来说并不难,但对于我这种基础很差、网络协议都是上学期自己补课的人来说属实有点难度,若不是启龙同学的帮助提供程序并解答我的部分疑惑,我怕是不可能按时完成这次作业。
    • 虽然我尽力想要弄明白程序的原理,但是我能力有限,再加上时间也不充裕(其他学科的作业和导师的学习任务也占据了不少时间),所以我只能大概描绘一下我运行这个程序时的流程,如果后续我还有余力的话,我会来更新博客。

    程序运行结果

    • 首先我来放一些程序运行结果,代码和分析在之后再放。
    • 程序准备开始运行
    • 开始抓包
    • 登陆了我的qq邮箱,来抓包
    • 可以看到抓到的文件

    程序代码和分析

    首先我先把的代码贴上

    constant.h
    
    #include <stdio.h>
    #include <pcap.h>
    #include <string.h>
    #include "util.h"
    
    #define INTRODUCTION "Author hanbing nudt.
    
    Simple packet dump"
    
    #define COMMAND_BUFFER_SIZE 50
    
    #define COMMAND_CODE_QUIT 1  /*command quit*/
    #define COMMAND_QUIT "quit"	
    
    #define COMMAND_CODE_LIST_ALL_DEVICE 2 /*list all valiable device*/
    #define COMMAND_LIST_ALL_DEVICE "show-device"
    
    #define COMMAND_CODE_SHOW_OPTIONS 3 /*show options of setting a filter*/
    #define COMMAND_SHOW_OPTIONS "show-options"
    
    #define COMMAND_CODE_SET 4
    #define COMMAND_SET "set"
    #define TOKEN " "
    
    #define COMMAND_CODE_BEGIN 5
    #define COMMAND_BEGIN "begin"
    
    • 这个头文件里都是一些宏定义,我就不详细说了。

    • 接下来是各个协议的头部定义
    #include <arpa/inet.h>
    
    #define ETHERNET_HEADER_LENGTH 14
    #define IP_HEADER_LENGTH 20
    #define IMCP_HEADER_LENGTH 8
    
    /*tls 头部定义*/
    struct tls_header
    {
      
    };
    
    /*UDP头部格式定义*/
    struct udp_header
    {
    	u_int16_t udp_source_port; //源端口号
    	u_int16_t udp_destination_port; //目的端口号
    	u_int16_t udp_length; //长度
    	u_int16_t udp_checksum ; //校验和
    };
    
    struct tcp_header
    {
    	u_int16_t tcp_source_port;
    	u_int16_t tcp_destination_port;
    	u_int32_t tcp_syn; //SYN number
    	u_int32_t tcp_ack; //ACK number
    	#ifdef WORDS_BEGENDIAN
      	u_int8_t 	tcp_offset:4,
      				tcp_reserved:4;
      	#else
      	u_int8_t 	tcp_reserved:4,
      				tcp_offset:4;
      	#endif
    
      	u_int8_t tcp_flags;
      	u_int16_t tcp_windows;
      	u_int16_t tcp_checksum;
      	u_int16_t tcp_urgent_pointer;
    };
    
    /*ICMP头部格式定义*/
    struct icmp_header
    {
    	u_int8_t icmp_type;
    	u_int8_t icmp_code;
    	u_int16_t icmp_checksum;
    	u_int16_t icmp_id;
    	u_int16_t icmp_sequence;
    };
    
    /*IP协议头部格式*/
    struct ip_header
    {
      #ifdef WORDS_BEGENDIAN
      u_int8_t  ip_version:4,  //ip协议版本
                ip_header_length:4; //ip协议首部长度
      #else
      u_int8_t  ip_header_length:4, //ip协议首部长度
                ip_version:4;  //ip协议版本
      #endif
      u_int8_t ip_tos; /*TOS服务质量*/                    
      u_int16_t ip_length; //总长度
      u_int16_t ip_id; //标识
      u_int16_t ip_off;//偏移
      u_int8_t ip_ttl; /*生存时间*/
      u_int8_t ip_protocol; //协议类型
      u_int16_t ip_checksum; //校验和
      struct in_addr ip_source_address; //源ip地址
      struct in_addr ip_destination_address; //目的ip地址
    
    };
    
    /*arp protocol format*/
    struct arp_header
    {
      u_int16_t arp_hardware_type; /*硬件地址类型 Ethernet is 1*/
      u_int16_t arp_protocol_type; /*网络层协议类型 ipv4 0x0800*/
      u_int8_t arp_hardware_length; /*硬件地址长度*/
      u_int8_t arp_protocol_length; /*网络层协议地址长度*/
      u_int16_t arp_operation_code; /*操作类型 1 request 2 reply*/
    
      u_int8_t arp_source_ethernet_address[6]; /*源以太网地址*/
      u_int8_t arp_source_ip_address [4]; /*源ip地址*/
      u_int8_t arp_destination_ethernet_address[6]; /*目的以太网地址*/
      u_int8_t arp_destination_ip_address [4]; /*目的ip地址*/
    };
    
    
    //util to get ethernet packets
    struct ether_header //data structure of ethernet protocol
    {
      u_int8_t ether_dhost[6]; //Destination address 
      u_int8_t ether_shost[6]; //Source address
      u_int16_t ether_type; //Ethernet type
    };
    
    
    void arp_protocol_packet_callback(u_char *argument, 
              const struct pcap_pkthdr *packet_header,
              const u_char *packet_content);
    
    void ethernet_protocol_packet_callback(u_char *argument, //arguments pass by user
              const struct pcap_pkthdr *packet_header,
              const u_char *packet_content);
    
    void ip_protocol_packet_callback(u_char *argument, //arguments pass by user
              const struct pcap_pkthdr *packet_header,
              const u_char *packet_content);
    
    void icmp_protocol_packet_callback(u_char *argument, //arguments pass by user
              const struct pcap_pkthdr *packet_header,
              const u_char *packet_content);
    
    
    void udp_protocol_packet_callback(u_char *argument, //arguments pass by user
              const struct pcap_pkthdr *packet_header,
              const u_char *packet_content);
    
    void tcp_protocol_packet_callback(u_char *argument, //arguments pass by user
              const struct pcap_pkthdr *packet_header,
              const u_char *packet_content);
    #endif
    
    • 这个文件里包含的就是各个文件的头部的结构体的定义。由于上学期我看的网络协议看的很糙,并且也没怎么复习,所有我又复习了下各个协议的头部格式。

    • IP头部

    • TCP头部

    • UDP头部

    • 以太网帧头部


    • 然后是callback.c文件。在这个文件中主要是对各个协议的分析

    • Callback.c里的函数

    • void tcp_protocol_packet_callback 输出源端口、目标端口、并根据端口判别应用层协议输出,输出标志位、输出窗口大小、输出校验和、输出紧急指针,总之把头部里能输出的都输出了

    • void udp_protocol_packet_callback 输出源端口、目标端口、并根据端口判别应用层协议输出,输出长度、输出校验和

    • void icmp_protocol_packet_callback 跳过IP协议头部,直接获取IP数据包中icmp协议,如果是回显请求或者回显应答数据包,就输出icmp的类型。然后统一输出标识符、序列号、校验和

    • void arp_protocol_packet_callback 输出硬件类型、协议类型、硬件长度、操作码、请求协议还是相应协议、arp还是rarp、源ip和mac,目标ip和mac

    • void ip_protocol_packet_callback 输出IP版本、头长度、总长度、服务类型、标识、偏移、TTL、校验和、源地址和目标地址、并判定传输层协议,然后扔到相应的callback函数中

    • void ethernet_protocol_packet_callback 输出目的mac地址和源mac地址,然后根据上层协议类型扔到ip或者arp的函数。

    #include "callback.h"
    
    static int number = 0;
    
    void tls_protocol_packet_callback(u_char *argument, //arguments pass by user
              const struct pcap_pkthdr *packet_header,
              const u_char *packet_content)
    {
    
    }
    
    void tcp_protocol_packet_callback(u_char *argument, //arguments pass by user
              const struct pcap_pkthdr *packet_header,
              const u_char *packet_content)
    {
      struct tcp_header *tcp_protocol;
      u_char flags;
      int header_length;
      u_short source_port;
      u_short destination_port;
      u_short windows;
      u_short urgent_pointer;
      u_int sequence;
      u_int acknowlegement;
      u_int16_t checksum;
      tcp_protocol=(struct tcp_protocol*)(packet_content+ETHERNET_HEADER_LENGTH+IP_HEADER_LENGTH);//以太头部长度和ip头部长度
      source_port = ntohs(tcp_protocol->tcp_source_port);//回调函数实现ip分析,找出tcp头部中的源端口号,下同
      destination_port = ntohs(tcp_protocol->tcp_destination_port);
      header_length = tcp_protocol->tcp_offset * 4;
      sequence = ntohs(tcp_protocol->tcp_syn);
      acknowlegement = ntohs(tcp_protocol->tcp_ack);
      windows = ntohs(tcp_protocol->tcp_windows);
      urgent_pointer = ntohs(tcp_protocol->tcp_windows);
      flags = tcp_protocol->tcp_flags;
      checksum = ntohs(tcp_protocol->tcp_checksum);
      printf("--------------------TCP Protocol (Transport Layer)--------------------------
    ");
      printf("Source Port: %d
    ",source_port );
      printf("Destination Port: %d
    ",destination_port );
      switch(destination_port) //判断上层协议 通过端口判断应用层协议
      {
        case 80:printf("HTTP protocol 
    ");break;
        case 21:printf("FTP protocol 
    ");break;
        case 23:printf("Telnet protocol 
    ");break;
        case 25:printf("SMTP protocol 
    ");break;
        case 110:printf("POP3 protocol
    ");break;
        case 443:printf("HTTPS protocol 
    ");break;
        default:break;
    
      }
    
      printf("Sequence Number: %u
    ",sequence );
      printf("Acknowlegement Number: %u
    ", acknowlegement ); //%u unsigned integer
      printf("Header Length: %d
    ",header_length );
      printf("Reserve: %d
    ",tcp_protocol->tcp_reserved );
    
      //提取标志位
      if (flags & 0x20)printf("URG");
      if (flags & 0x01)printf("FIN");
      if (flags & 0x04)printf("RST");
      if (flags & 0x08)printf("PSH");
      if (flags & 0x10)printf("ACK");
      if (flags & 0x02)printf("SYN");
      printf("
    ");
    
      printf("Window Size: %d
    ",windows );
      printf("Checksum: %d
    ", checksum);
      printf("Urgent Pointer: %d
    ",urgent_pointer );
    
      switch(destination_port) //判断上层协议
      {
        case 443:
          tls_protocol_packet_callback(argument,packet_header,packet_content);
          break;
        default:
          break;
    
      }
    }
    
    void udp_protocol_packet_callback(u_char *argument, //arguments pass by user
              const struct pcap_pkthdr *packet_header,
              const u_char *packet_content)
    {
      struct udp_header *udp_protocol; //UDP协议变量
      u_short source_port; //源端口号
      u_short destination_port; //目的端口号
      u_short length; //长度
      /*获得ICMP协议数据内容,跳过以太网协议与ip协议部分*/
      udp_protocol = (struct udp_header *)(packet_content+ETHERNET_HEADER_LENGTH+IP_HEADER_LENGTH);
      source_port = ntohs(udp_protocol->udp_source_port);
      destination_port = ntohs(udp_protocol->udp_destination_port);
      length = ntohs(udp_protocol->udp_length);
      printf("-------------------------UDP Protocol (Transport Layer) ----------------------
    ");
      printf("Source port: %d
    ", source_port);
      printf("Destination port: %d
    ", destination_port);
      switch(destination_port)
      {
        //NetBios数据报服务
        case 138: printf("NETBIOS Datagram Service
    "); break;
        case 137: printf("NETBIOS Name Service
    "); break;
        case 139: printf("NETBIOS Session Service
    "); break;
        case 53:printf("name-domain server 
    ");break;
        default:break;//其他端口号在此没有分析,后续版本会添加
    
      }
      printf("Length:%d 
    ", length );
      printf("Checksum: %d
    ", ntohs(udp_protocol->udp_checksum)); //获得校验和
    
    }
    
    
    
    void icmp_protocol_packet_callback(u_char *argument, //arguments pass by user
              const struct pcap_pkthdr *packet_header,
              const u_char *packet_content)
    {
      struct icmp_header *icmp_protocol;
      /*获得ICMP协议数据内容,跳过以太网协议与ip协议部分*/
      icmp_protocol = (struct icmp_header *) (packet_content+ETHERNET_HEADER_LENGTH+IP_HEADER_LENGTH);
      printf("---------------ICMP Protocol (Transport Layer)---------------------");
      printf("ICMP Type: %d
    ",icmp_protocol->icmp_type );
      switch(icmp_protocol->icmp_type) //ICMP数据包类型较多,待扩展
      {
        case 8://回显请求ICMP数据包
        printf("ICMP Echo REquest Protocol 
    ");
        printf("ICMP Identifier: %s
    ", icmp_protocol->icmp_id);
        printf("ICMP Sequence Number: %s
    ", icmp_protocol->icmp_sequence);
        break;
        case 0://回显应答数据包
        printf("ICMP Echo Reply Protocol 
    ");
        printf("ICMP Identifier: %s
    ", icmp_protocol->icmp_id);
        printf("ICMP Sequence Number: %s
    ", icmp_protocol->icmp_sequence);
        break;
        default:
        printf("Header Data %s%s
    ", icmp_protocol->icmp_id,icmp_protocol->icmp_sequence);
    
      }
      printf("ICMP Checksum:%d
    ",ntohs(icmp_protocol->icmp_checksum) );
      printf("ICMP Payload: %s", packet_content+
        ETHERNET_HEADER_LENGTH+IP_HEADER_LENGTH+IMCP_HEADER_LENGTH);
    }
    
    /*arp协议分析回调函数*/
    void arp_protocol_packet_callback(u_char *argument, 
              const struct pcap_pkthdr *packet_header,
              const u_char *packet_content)
    {
      struct arp_header *arp_protocol; //协议头变量
      u_short protocol_type; //协议类型
      u_short hardware_type; //硬件协议类型
      u_short operation_code; //操作类型
      u_char *mac_string; //以太网地址
      struct in_addr source_ip_address; 
      struct in_addr destination_ip_address;
    
      u_char hardware_length; //硬件地址长度
      u_char protocol_length; //协议地址长度
    
      printf("----------  ARP Protocol (Network Layer) ---------------
    ");
      /*获得arp协议数据。逐一在这里要跳过以太网数据部分*/
      arp_protocol = (struct arp_header *)(packet_content+ETHERNET_HEADER_LENGTH);
    
      /*使用ntohs函数将网络字节序转换为本机字节序*/
      hardware_type =  ntohs(arp_protocol->arp_hardware_type);
      protocol_type = ntohs(arp_protocol->arp_protocol_type);
      operation_code = ntohs(arp_protocol->arp_operation_code);
    
      hardware_length = arp_protocol->arp_hardware_length;
      protocol_length = arp_protocol->arp_protocol_length;
    
      printf("ARP Hardware Type: %d
    ", hardware_type);//输出硬件类型
      printf("ARP Protocol Type: %d
    ",protocol_type);//输出协议类型
      printf("ARP Hardware Length: %d
    ", hardware_length);//输出硬件长度
      printf("ARP Operation: %d
    ", operation_code);//输出操作码
      switch(operation_code){//根据操作吗判别清秀协议还是响应协议,是arp还是逆向的rarp
        case 1: printf("ARP Request Protocol
    "); break;
        case 2: printf("ARP Reply Protocol
    "); break;
        case 3: printf("RARP Request Protocol
    "); break;
        case 4: printf("RARP Reply Protocol
    "); break;
        default: break;
      }
      printf("Ethernet Source Address is : 
    ");
      mac_string = arp_protocol->arp_source_ethernet_address;
      printf("%02x:%02x:%02x:%02x:%02x:%02x:
    ",*(mac_string),
      *(mac_string+1),*(mac_string+2),*(mac_string+3),*(mac_string+4),
      *(mac_string+5) );
      memcpy((void *) &source_ip_address, (void *) &arp_protocol->
          arp_source_ip_address, sizeof(struct in_addr));
      printf("Source IP Address: %s
    ", inet_ntoa(source_ip_address));
      printf("Ethernet destination_ip_address Address is : 
    ");
      mac_string = arp_protocol->arp_destination_ethernet_address;
      printf("%02x:%02x:%02x:%02x:%02x:%02x
    ",*(mac_string),
      *(mac_string+1),*(mac_string+2),*(mac_string+3),*(mac_string+4),
      *(mac_string+5) );
      memcpy((void *) &destination_ip_address, (void *) &arp_protocol->
          arp_destination_ip_address, sizeof(struct in_addr));
      printf("Destination IP Address: %s
    ", inet_ntoa(destination_ip_address));
    
    }
    
    
    /*回调函数实现ip协议包分析*/
    void ip_protocol_packet_callback(u_char *argument, //arguments pass by user
              const struct pcap_pkthdr *packet_header,
              const u_char *packet_content)
    {
      struct ip_header *ip_protocol; 
      u_int header_length; 
      u_int offset;
      u_char tos;
      u_int16_t checksum;
      /*去掉以太网头部,获得ip协议数据内容*/
      ip_protocol = (struct ip_header *)(packet_content + ETHERNET_HEADER_LENGTH);
      checksum = ntohs(ip_protocol->ip_checksum);
      header_length = ip_protocol->ip_header_length*4;
      tos = ip_protocol->ip_tos;
      offset = ntohs(ip_protocol->ip_off);
      printf("------------------IP Protocol (Network Layer)----------------------
    ");  
      printf("IP Version: %d
    ",ip_protocol->ip_version);
      printf("Header_length: %d
    ",header_length);
      printf("Tos:%d
    ", tos);
      printf("Total length: %d
    ", ntohs(ip_protocol->ip_length));
      printf("Identification: %d
    ",ntohs(ip_protocol->ip_id) );
      printf("offset: %d
    ",(offset & 0x1fff)*8 );
      printf("TTL: %d
    ",ip_protocol->ip_ttl );
      printf("Protocol: %d
    ",ip_protocol->ip_protocol );
    
      switch(ip_protocol->ip_protocol)
      {
        case 6: printf("The Transport Layer Protocol is TCP
    ");break;
        case 17: printf("The Transport layer Protocol is UDP
    ");break;
        case 1: printf("The Transport layer Protocol is ICMP
    ");break;
        default: 
          break;
      }
      printf("Header checksum: %d
    ", checksum);
      printf("Source address: %s
    ",inet_ntoa(ip_protocol->ip_source_address));
      printf("Destination address: %s
    ", inet_ntoa(ip_protocol->ip_destination_address));
    
      switch(ip_protocol->ip_protocol)
      {
        case 6: tcp_protocol_packet_callback(argument,packet_header,packet_content);break;
        case 17: udp_protocol_packet_callback(argument,packet_header,packet_content);break;
        case 1: icmp_protocol_packet_callback(argument,packet_header,packet_content);break;
        default: 
          break;
      }
    
    }
    
    
    /*回调函数实现以太网协议分析*/
    
    void ethernet_protocol_packet_callback(u_char *argument, //arguments pass by user
              const struct pcap_pkthdr *packet_header,
              const u_char *packet_content){
    
      pcap_dump(arguement, packet_header, packet_content);
    
      number++;
      printf("
    ");
      printf("
    ");
      printf("The num %d packets
    ", number);
    
      u_short ethernet_type; //以太网类型
      struct ether_header *ethernet_protocol; //以太网协议类型
      u_char *mac_string; //以太网地址
      static int packet_number = 1;
      printf("--------------------Ethernet Protocol (Link Layer)-------------------
    ");
    
      ethernet_protocol = (struct ethernet_header *)packet_content;
    
      /*获得以太网协议数据*/
      printf("Ethernet type is : 
    ");
      ethernet_type = ntohs(ethernet_protocol->ether_type);//获得以太网类型
      printf("%04x
    ",ethernet_type );
      switch(ethernet_type)
      {
        case 0x0800: printf("The network layer is IP protocol
    ");break;
        case 0x0806: printf("The network layer is ARP protocol
    ");break;
        case 0x0835: printf("The network layer is RARP protocol
    ");break;
      }
        /*获得源以太网地址*/
        printf("Mac Source Address is : 
    ");
        mac_string = ethernet_protocol->ether_shost;
        printf("%02x:%02x:%02x:%02x:%02x:%02x
    ",*(mac_string),
      *(mac_string+1),*(mac_string+2),*(mac_string+3),*(mac_string+4),
      *(mac_string+5) );
    
    
        /*获得目的以太网地址*/
        printf("Mac Destination Address is : 
    ");
        mac_string = ethernet_protocol->ether_dhost;
        printf("%02x:%02x:%02x:%02x:%02x:%02x
    ",*(mac_string),
      *(mac_string+1),*(mac_string+2),*(mac_string+3),*(mac_string+4),
      *(mac_string+5) );
         
         /*调用上层协议分析回调函数*/
        switch(ethernet_type)
        {
          case 0x0800: ip_protocol_packet_callback(argument,packet_header,packet_content);
                        break;
          case 0x0806: arp_protocol_packet_callback(argument,packet_header,packet_content);
                        break;
          case 0x0835: break;
          default: break;
        }
      
    
      printf("-------------------------------------------------------------------------
    ");
    
    }
    
    • 可以看出来上面的函数层层递进得来分析协议,先是对以太网帧进行分析,然后根据分析得出来的上层协议,来转到IP或者ARP的分析函数。

    • 然后在IP的分析函数中,也是通过分析数据,来转到TCP、UDP或者ICMP的函数中。


    • 分析完上面的几个文件之后,我是从main函数开始,将我的抓包过程的所经历的程序分析了一遍。

    • 首先是main.c文件

    
    #include "constant.h"
    
    static char buffer[COMMAND_BUFFER_SIZE];
    static int command_code;
    static filter_options_t options;
    
    void init_interpreter(){
    	puts(INTRODUCTION);
    }
    
    void PrintUsage(){
    	printf("%s
    ", USAGE);
    }
    
    void show_options(){
    	printf("过滤规则: %s
    ", options.filter);
    	printf("网络设备: %s
    ",options.device);
    }
    
    int ParseCommandLine(char *command){
    
    	if (strcmp(command,COMMAND_QUIT) == 0)
    	{
    		command_code = COMMAND_CODE_QUIT;
    		return 0;
    	}
    	else if (strcmp(command,COMMAND_LIST_ALL_DEVICE) == 0)
    	{
    		command_code = COMMAND_CODE_LIST_ALL_DEVICE;
    		return 0;
    	}
    	else if (strcmp(command,COMMAND_SHOW_OPTIONS) == 0)
    	{
    		command_code = COMMAND_CODE_SHOW_OPTIONS;
    		return 0;
    	}
    	else if(strcmp(command,COMMAND_BEGIN) == 0){
    		command_code = COMMAND_CODE_BEGIN;
    		return 0;
    	}
    	else{
    		char *tmp = NULL;
    		tmp = strtok(command,TOKEN);
    		if (strcmp(tmp,COMMAND_SET) == 0)
    		{
    			if(pares_option_setting()){
    				command_code = COMMAND_CODE_SET;
    				return 0;
    			}
    		}
    	}
    	command_code = 0;
    	return 1;
    }
    
    int pares_option_setting(){
    	char *tmp;
    	char *option;
    	tmp = strtok(NULL,TOKEN);
    	if (!tmp)
    	{
    		return 0; //false
    	}
    	option = strtok(NULL,TOKEN);
    	if (!option)
    	{
    		return 0; //false
    	}
    	if (strtok(NULL,TOKEN))
    	{
    		return 0;
    	}
    
    	if (!strcmp(tmp,"device"))
    	{
    		strcpy(options.device,option);
    		return 1;
    	}
    
    	else if(!strcmp(tmp,"filter"))
    	{
    		strcpy(options.filter,option);
    		return 1;
    	}
    
    	else if(!strcmp(tmp,"path"))
    	{
    		strcpy(options.path,option);
    		return 1;
    	}
    
    	else
    	{
    		return 0;//false
    	}
    
    
    }
    
    int CommandDispacther(){
    	switch(command_code){
    		case COMMAND_CODE_QUIT:
    			return 0;  //return status code 0 when quit
    		case COMMAND_CODE_LIST_ALL_DEVICE:
    			findalldevs();
    			return 1;
    		case COMMAND_CODE_SHOW_OPTIONS:
    			show_options();
    			return 1;
    		case COMMAND_CODE_SET:
    			return 1;
    		case COMMAND_CODE_BEGIN:
    			capture_packets(&options);
    			return 1;
    		default:
    			return 0;	//defalt retrun true
    	}
    }
    
    
    
    int main(int argc, char const *argv[])
    {
    	int status = 1;
    
    	init_interpreter();
    	do{
    		printf(">>");
    		gets(buffer);
    		
    		/*Parse args options*/
    		if (ParseCommandLine(buffer)){
    			PrintUsage();
    		}else{
    			status = CommandDispacther();
    		}
    	} while (status);
    	
    
    	return 1;
    }
    
    • 这里只看main函数的话是非常的简洁,只有这几行,所以我的运行过程也很简单(如果难的话我应该就看不懂了)

    • main函数里首先定义了一个作用的变量status,用于do while循环。然后void init_interpreter()就是输出了宏定义的一句话(这个函数删了也没什么影响吧,只是输出一句话了)。然后开始do while 循环。

    • 在我的程序里,我第一个输入的bufferset device eth0这个eth0就是我的网卡。接下看ParseCommandLine(buffer)。这个函数也在main.c里面,可以在上面的代码里找到。我输入的很显然不是这些任何一个宏定义,然后转到else。接着在else里转到下一个pares_option_setting函数,在这里进行了strcpy(options.device,option),将网卡保存了下来。之后可以看到该函数返回了1,然后继续向上推,上一个函数返回0,并且将command_code设置为一个宏定义。接下来回到main函数,因为if返回0,执行else,在CommandDispacther里又可以得到返回1.也就是继续进行do while循环

    • 其实上面的一大串,不过是储存了我设置的网卡,然后继续循环。所以接下来我输入的set path 也就不再罗里吧嗦的说了,可以顺着看。

    • 第三次循环我输入begin。顺着运行可以看到,最后执行了capture_packets(&options)这个函数再另一个文件里:

    int findalldevs(){
    	pcap_if_t *alldevs;//网卡链表里的一个元素
    	pcap_if_t *d;
    	char *s;
    	bpf_u_int32 net,mask;
    	int exit_status = 0;
    
    	char errbuf[PCAP_ERRBUF_SIZE+1];
    	if (pcap_findalldevs(&alldevs, errbuf) == -1)
    	{
    		fprintf(stderr,"Error in pcap_findalldevs: %s
    ",errbuf);
        	return 1;
    	}
    	for(d=alldevs;d;d=d->next)
      	{
        	if (!ifprint(d)){
        		return 1;
        	}
    
      	}
      	if ( (s = pcap_lookupdev(errbuf)) == NULL)
      	{
        	fprintf(stderr,"Error in pcap_lookupdev: %s
    ",errbuf);
        	exit_status = 2;
      	}
      	else
      	{
        	printf("Preferred device name: %s
    ",s);
     	}
    
     	 if (pcap_lookupnet(s, &net, &mask, errbuf) < 0)
      	{
       	 	fprintf(stderr,"Error in pcap_lookupnet: %s
    ",errbuf);
       		exit_status = 2;
      	}
      	else
      	{
        	printf("Preferred device is on network: %s/%s
    ",iptos(net), iptos(mask));
      	}
      	return exit_status;
    
    }
    void capture_packets(struct filter_options *options){
      char error_content[PCAP_ERRBUF_SIZE];
      pcap_t *pcap_handle; 
      bpf_u_int32 net_mask; //netmask
      bpf_u_int32 net_ip; //net ip
      char *net_interface;
    
      struct bpf_program bpf_filter; //bpf过滤规则
      char *bpf_filter_string = options->filter; //bpf过滤规则
    
      //net_interface = pcap_lookupdev(error_content); /*获取网络接口*/
      net_interface = options->device;
      printf("net_interface :%s
    ", net_interface);
    
      /*获取网络地址和掩码地址*/
      pcap_lookupnet(net_interface,//该函数用于获得网卡所在网络的网络地址和子网掩码。
                    &net_ip,
                    &net_mask,
                    error_content);
      /*打开网络接口*/
      pcap_handle = pcap_open_live(net_interface,// 该函数用于打开指定设备的网络捕获,获得数据包捕获描述字
                                    BUFSIZ,
                                    1, /*混杂模式*/
                                    0, /*等待实践*/
                                    error_content);
    
      if (!pcap_handle)
      {
        printf("打开网络接口失败,请检查输入的网络接口是否存在,或者是否具有权限打开此网络接口。
    ");
        return;
      }
    
      /*编译并设置bpf过滤规则*/
      if (pcap_compile(pcap_handle, &bpf_filter,bpf_filter_string,0,net_mask))
      {
          printf("请检查你的输入规则是否有误。
    ");
          return;
      }
      
      pcap_setfilter(pcap_handle,&bpf_filter);//函数用于指定一个过滤程序,出错时返回-1
    
      if (pcap_datalink(pcap_handle) != DLT_EN10MB)
      {
        return;
      }
    
      pcap_dumper_t* out_pcap = NULL;
      out_pcap  = pcap_dump_open(pcap_handle,options->path);//打开用于保存数据包的文件,用于写入
    
      pcap_loop(pcap_handle,//用来捕获数据包时用的。捕获了符合要求的数据包就交给回调函数。
                ,ethernet_protocol_packet_callback //开始一层层揭开
                ,(u_char *)out_pcap); //pass arguments to callback
      pcap_close(pcap_handle);//关闭指针相应的文件,释放资源
      pcap_dump_close(out_pcap);//关闭被打开的文件
    }
    
    
    • 可以看到这里开始有了很多的pcap的函数和数据类型。我再网上找了一些大致的简介。

    • pcap_t 一种结构体。详细参考来自这里

    • 关于函数的简介,我在尝试读程序的时候在注释里写了一些,程序本身也带有一些注释,并且网上对一些函数的详细功能描述也是不清不楚,甚至有的还有歧义,我只是结合这个程序把我认为正确的解释写到了注释里,但是我没有经过实践去验证,就不详细写了。

    • 然后注意ethernet_protocol_packet_callback,开始使用回调函数。在前面我也提到,在以太网帧解析完毕之后会一层层传递,也就是这一句函数就把这个数据解释完毕了。

    • 然后再看回mian函数,这个时候就应该输入COMMAND_QUIT的宏定义准备退出了。但是我每次都是CTRL+C直接结束,所以没有截图。。。

    • 可以看到我对这个程序并没有很全面的掌握。比如我在运行时没用到的程序。比如lipacp函数的详细原理(这个我尽力看了,但是我真的在短时间内看不很懂,好多基础知识都不了解,考虑自己的似懂非懂的状态不好意思献丑,所以我没有解释libpacp的函数)。之后有时间我会尽力补充。


    二、

    找一个网站或者搭建一个本地网站,登录网站,并嗅探,分析出账号和密码,结果截图1-2张。

    • 由于我不会搭建网站,所以就想登录别的网站然后抓包。但是尴尬的是所有的网站都在加密,抓下来我也只能知道密文。这个让人很是头疼。

    • 在同学的帮助下,我了解了POP3的服务是明文。我就下载了一个foxmail,然后在用foxmail登录的过程取消了ssl加密

    • 结果

    • 当然这里的不是我的密码,是pop3的授权码,我已经禁止pop3了所以没有打马赛克。

    三、

    抓取手机App的登录过程数据包,分析账号和密码。

    • 首先,在上周的作业中有学到,现在的都是交换机,有“MAC地址-端口映射表”,很难用电脑来抓取手机的数据包,除非“洪泛攻击”、“MAC欺骗”、“ARP欺骗"三种方法。但是我一种都不会。前面也说过,最近时间属实有点紧迫,所以暂时放弃了学习这三种方法,直接用手机连接了电脑的热点。
    • 这个加密就更加愁人了,启龙同学告诉我苹果的app store似乎不允许明文传输。
    • 这是登录邮箱app抓下来的包
    • 我不像建国一样有那么深厚的密码学功底,不可能在这个周末就解密出来明文。而我又找不到明文传输的APP,所以我只能退而求其次,采用了大家都用的TIM,至少能抓个账号的明文。
    • 然后抓取数据包,这是结果:
  • 相关阅读:
    mysql workbench 建表时PK, NN, UQ, BIN, UN, ZF, AI
    Asan检测内存读越界
    C 实现 C++ 的面向对象特性(封装、继承、多态)
    VIBE算法
    Go 大坑 nil
    求二叉树中节点的最大距离
    计算[1,N]范围内含有7的数字的个数
    一组便于创建线程和线程池的简单封装函数
    用C#执行doc命令
    可以自由停靠的窗体!
  • 原文地址:https://www.cnblogs.com/maomutang/p/12587762.html
Copyright © 2011-2022 走看看