当前位置:   article > 正文

利用PCAP实现网络数据截获修改(二)_pcap抓包 什么时候不会截断原有报文

pcap抓包 什么时候不会截断原有报文

上一边我们实现了利用PCAP,将报文从一个网卡复制到另一个网卡。实现了一种截断正常网络传输而不影响原有传输的一种方案。
考虑到网络数据是带有校验的,如果我们修改了tcp的payload部分,那么则需要重新进行校验,所以本篇主要研究了对TCP和UDP部分数据的校验计算。
首先简单介绍一下网上的关于校验和的计算,
TCP和UDP数据基本一样,公式就是伪头部+tcp(或udp)的全部数据,计算和放入一个unsigned int的数字中,然后如果高16位有数据,则将其移入低16位加入,循环操作直到高16位没有数据为止,然后取反作为校验和。

伪头部的结构,共12个字节。

typedef struct _check_subhdr         // udp计算checksum时的 亚头部: 4 byte源ip地址 + 4 byte目的ip地址 + 0x00 + 1 byte协议 + UDP 长度(2byte)
{
    unsigned int  	src_ip; 
    unsigned int  	dst_ip; 
    char     		mbz;           // must be zero
    char     		protocol; 
    unsigned short  len;           // 这里的长度是指  udp packet中  udp头部和数据部分的总长度
} check_subhdr;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

校验和的计算函数如下

u_short core_checksum(u_short *buffer,int size)  
{  
    unsigned int cksum=0;  
    while(size>1)  
    {  
    	unsigned short tmp=*buffer++;
        cksum+=tmp;  
        size-=sizeof(u_short); 
		
		//printf("0x%04x+",tmp);
    }  
    if(size)  
    {  
        cksum+=*(u_char *)buffer;  
    }  
	//printf("=cksum:%08x\n",cksum);
    //将32位数转换成16   
    while (cksum>>16) 
	{
		cksum=(cksum>>16)+(cksum & 0xffff); 
	}
	
	//printf("cksum2:%08x\n",cksum);
    return (u_short) (~cksum);  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

计算TCP报文的TCP部分校验的函数如下

u_short get_tcp_checksum(struct iphdr *ipptr,struct tcphdr *tcpptr,int pkt_len) 
{
	int i=0;
	char cleancnum[2]={0,0};
	//u_short tcp_part_len = pkt_len-sizeof(struct ether_header)-sizeof(struct iphdr);    
	u_short tcp_part_len = ntohs(ipptr->tot_len)-(ipptr->ihl*4);

    check_subhdr tcp_subhdr; 
    tcp_subhdr.protocol = ipptr->protocol; 
    tcp_subhdr.dst_ip = ipptr->daddr; 
    tcp_subhdr.src_ip = ipptr->saddr; 
    tcp_subhdr.mbz = 0x00; 
    tcp_subhdr.len = htons(tcp_part_len); 

    int subhdr_len = sizeof(check_subhdr); 
    int buf_size = tcp_part_len + subhdr_len;         // 亚包头 + udp包头 + 数据部分的总长度
    if (pkt_len < buf_size)
        return 0; 
    u_char* buffer = (u_char*)malloc(buf_size); 
    memset(buffer, 0x00, buf_size); 

    memcpy(buffer, (char*)&tcp_subhdr, subhdr_len); 
    //memcpy(buffer + subhdr_len, (char*)udpptr, udp_part_len); 

	//先拷贝16个字节有效数据,
	memcpy(buffer + subhdr_len, (char*)tcpptr, 16); 
	//拷贝两个00作为校验码
	memcpy(buffer + subhdr_len + 16, (char*)cleancnum, 2); 
	//拷贝剩余部分数据
	memcpy(buffer + subhdr_len + 18, ((char*)tcpptr)+18, tcp_part_len-18); 

	u_short checksum=0;
	checksum = core_checksum((u_short *)buffer,buf_size);
	
    free(buffer);
    return checksum;  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

这里遇到了一个思考两天才解决的问题
//u_short tcp_part_len = pkt_len-sizeof(struct ether_header)-sizeof(struct iphdr);
u_short tcp_part_len = ntohs(ipptr->tot_len)-(ipptr->ihl*4);
从网上找到的这个tcp部分的长度计算,正常情况下,我们就这么算,除去eth头和IP头,剩下的部分就是所有tcp的字段,猛一看没什么问题,实际用起来,就会发现,偶尔就会有一些报文计算出来的校验和和报文里的不一致,但是源报文的pcap在wireshark中,并不会出现校验错误。这个问题一直困扰了我一天,直到我发现有些报文的IP头中的数据总长度,存在异常,
在这里插入图片描述

如图,IP部分总长度表示40,即IP和后面的TCP加起来一共40个字节,但是显然后面还有6个字节,按照开始的计算方式,TCP长度是26个,并不是20,所以算来算去,总是出错。
最终调整为
u_short tcp_part_len = ntohs(ipptr->tot_len)-(ipptr->ihl*4);
问题得以解决,所以不能看你收到了多少字节,要看IP头部告诉你,应该是多少字节。

这样,本篇到此,实现了数据的TCP和UDP部分校验和的计算,为后面修改报文数据,打下了基础。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/487236
推荐阅读
相关标签
  

闽ICP备14008679号