实践三 网络嗅探与协议分析

一、

根据教材参考代码,编写有个简单网络抓包工具。要求核心代码和运行结果截图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,至少能抓个账号的明文。
  • 然后抓取数据包,这是结果:
原文地址:https://www.cnblogs.com/maomutang/p/12587762.html