ipv4数据报文中修改的来源ip或目的ip后,一般需要修改对应的校验码。首先ip校验码是最基础的,然后因为TCP/UDP对应的校验码会根据伪报文头检查(其中包含src ip 和 dst ip),所以也需要修改tcp/udp报文的校验码。这里修复了一些其他文章中的BUG,例如缓存溢出、构造TCP/UDP伪报文采用的参数等,通过实验能够正常运行。
1.IP检验码
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 38 39 40 41 |
unsigned int Checksum(unsigned int cksum, void *pBuffer, unsigned int size) { unsigned int num = 0; unsigned char *p = (unsigned char *)pBuffer; if ((NULL == pBuffer) || (0 == size)) { return cksum; } while (size > 1) { cksum += ((unsigned short)p[num] << 8 & 0xff00) | (unsigned short)(p[num + 1] & 0x00FF); size -= 2; num += 2; } if (size > 0) { cksum += ((unsigned short)p[num] << 8) & 0xFFFF; num += 1; } while (cksum >> 16) { cksum = (cksum & 0xFFFF) + (cksum >> 16); } return cksum; } unsigned short ChangeIpv4Checksum(char *ipHeader) { unsigned short ipHeadLen = (ipHeader[0] & 0x0F) << 2; ipHeader[10] = 0; ipHeader[11] = 0; unsigned int sum = Checksum(0, (void *)(&ipHeader[0]), ipHeadLen); unsigned int tmp = ~sum; ipHeader[10] = (unsigned char)(tmp >> 8); ipHeader[11] = (unsigned char)(tmp); return ipHeadLen; } |
2.TCP/UDP校验码
执行修改当前数据包TCP或UDP校验码
1 2 3 4 5 6 7 |
//获取Tcp/Udp报文首地址指针,ethPkt表示ipv4报文首地址,0x45 00 ..... unsigned char *header = ðPkt[ipHeadLen]; //计算ipv4报文中Tcp/Udp报文长度 unsigned short len = ntohs(*(unsigned short*)(ðPkt[2])) - ipHeadLen; //根据修改的源IP或目的IP来计算校验码,ethPkt[9]表示tcp或协议类型 ChangeTcpUdpChecksum(header, source_ip.to_uint(), target_ip.to_uint(), ethPkt[9], len); |
计算TCP或UDP校验码函数,其中构造TCP/UDP伪报头中采用长度为TCP/UDP段之后报文长度,ptc表示采用哪种协议。
Checksum函数和IP一样,都是计算校验和求反。
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 38 39 40 41 42 |
struct psd_header { unsigned int saddr; //tcp source addr unsigned int daddr; //tcp target addr char mbz; //NULL char ptcl; //protocol type unsigned short tcpl; //TCP length = headerLen + bodyLen; }; /* * Header tcp/udp header, * len is tcp/udp packet length ,contains data segement 这里重点,计算伪报文头的传递长度中包含数据段长度 * ptc is tcp/udp protocol code ,0x06 to tcp or 0x11 to udp * */ void ChangeTcpUdpChecksum(unsigned char *Header, unsigned int ui_source_ip, unsigned int ui_target_ip, char ptc, unsigned short len) { unsigned char SendBuf[2048] = {0}; unsigned short header_len = (Header[12] & 0xFF) >> 2; Header[16]=0; Header[17]=0; struct psd_header *p_psd = NULL; p_psd = (struct psd_header *)malloc(sizeof(struct psd_header)); p_psd->saddr = (unsigned int)htonl(ui_source_ip); p_psd->daddr = (unsigned int)htonl(ui_target_ip); p_psd->mbz = (char)0x00; p_psd->ptcl = ptc; p_psd->tcpl = (unsigned short)htons(len); //copy and compute checksum memcpy(SendBuf,p_psd,sizeof(struct psd_header)); memcpy(SendBuf+sizeof(struct psd_header),Header,len); unsigned int tcp_sum=Checksum(0,(void *)&SendBuf,sizeof(struct psd_header)+len); unsigned int tcp_tmp = ~tcp_sum; Header[16]=(unsigned char)(tcp_tmp >> 8); Header[17]=(unsigned char)(tcp_tmp); free(p_psd); return ; } |
参考引用:
https://blog.csdn.net/jiangqin115/article/details/39315085
https://blog.csdn.net/wangshiqilin_fjy/article/details/7889316
https://blog.csdn.net/zhangskd/article/details/11770647
微信赞赏
支付宝赞赏