ipv4数据报文中修改的来源ip或目的ip后,一般需要修改对应的校验码。首先ip校验码是最基础的,然后因为TCP/UDP对应的校验码会根据伪报文头检查(其中包含src ip 和 dst ip),所以也需要修改tcp/udp报文的校验码。这里修复了一些其他文章中的BUG,例如缓存溢出、构造TCP/UDP伪报文采用的参数等,通过实验能够正常运行。
1.IP检验码
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校验码
//获取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一样,都是计算校验和求反。
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