NDIS网络封包的研究
来源:优易学  2011-12-26 16:39:55   【优易学:中国教育考试门户网】   资料下载   IT书店

  如果是PSH包则表示发送数据,开始我只是修改了数据的第一位,修改为大写字母A,结果发现接收的时候接收不到,想了很久没想到原因,后来抓包发现数据实际是到达了,但是因为数据修改了,校验和就不正确了,所以接收方就将数据包丢弃了,而发送方不知道,则做超时处理,并大概在6秒以后重新发送,如此往复(从这点看出TCP的稳定性确实非UDP可比,不会出现丢包的问题,不过又从一个侧面来看,似乎也是一个很强大的拒绝服务攻击方式)。 计算校验和又费了我很多时间,开始参照了一些DDOS工具的校验和算法,但是每次算出来的都不对。后来发现实际TCP校验和的算法应该是 PSD伪头部+TCP头部+数据 整体来进行 checksum 代码如下:
  ptcp_header = (PTCP_HEADER)(PacketContent + sizeof(ETHHDR) + sizeof(IP_HEADER));
  tcphdrlen = HTONS(ipPacket>ip.total_len) sizeof(IP_HEADER);
  memcpy(pCheckSum, ptcp_header, tcphdrlen);
  KdPrint(("SizeofTCP: %d TcpHdrLen %d\n", sizeof(TCP_HEADER), tcphdrlen));
  //修改目的地址和目的端口,校验和
  ((PTCP_HEADER)pCheckSum)>th_sum = 0;
  //填充TCP伪首部
  psd_header.saddr = ipPacket>ip.sourceIP; //源地址
  psd_header.daddr = ipPacket>ip.destIP; //目的地址
  psd_header.mbz = 0;
  psd_header.ptcl = 6/*IPPROTO_TCP*/;//协议类型
  psd_header.tcpl = HTONS(sizeof(TCP_HEADER)); //TCP首部长度
  //计算TCP首部校验和
  NdisZeroMemory(SendBuf, 2048);
  NdisMoveMemory(SendBuf, &psd_header, sizeof(psd_header));
  NdisMoveMemory(SendBuf+sizeof(psd_header), pCheckSum , tcphdrlen);
  tcp_header.th_sum = checksum((USHORT*)SendBuf,sizeof(psd_header)+tcphdrlen);
  tcp_header.th_sum = HTONS(HTONS(tcp_header.th_sum) DataSize);
  //KdPrint(("网络代码计算校验和: [0x%.4x] 原校验和: [0x%.4x]\n", tcp_header.th_sum, ipPacket>tcp.th_sum));
  ipPacket>tcp.th_sum = tcp_header.th_sum;
  因为 Intel 的字节序和网络字节序是反的,所以多次用到HTONS这个宏,因为这个是驱动,没有办法用 winsock2.h 所以只有网上找了个宏来用。
  开始算出来还是不对,不过后来发现每次修改后的数据在ethereal显示的正确的校验和是算出来的校验和减去数据的长度,所以后面减去了一个 DataSize 测试发现修改数据可以实现了,下面要改改,改为添加16字节数据,先是将数据拷贝到数据包里,然后重新计算TCP校验和,不过问题又出来了,测试发现又出现接不到数据的问题了,抓包发现这次数据是添加了,但是ethereal显示还是以前的数据长度,又仔细看了下数据包,发现IP头有个值表示的是整个数据包的长度除开ETH头也就是说长度是 IP头+TCP头+数据,所以又修改了这个值,结果还是不行,继续抓包分析。发现IP头的校验又不正确了。 参见某些DDOS的代码,计算出来还是不对,而且差距甚远。。。。。郁闷了很久,他的代码如下:
  memcpy(SendBuf,&ip_header,sizeof(ip_header));
  memcpy(SendBuf+sizeof(ip_header),&tcp_header,sizeof(tcp_header));
  memset(SendBuf+sizeof(ip_header)+sizeof(tcp_header),0,4);
  datasize=sizeof(ip_header)+sizeof(tcp_header);
  ip_header.checksum=checksum((USHORT *)SendBuf,datasize);
  他是将IP头和TCP头进行计算,可惜不对。
  网上找了很多代码都是这个方法,想了很久想不到为什么错误。 后来因为一些事情出去了一下,回来时候大脑稍微清醒点了,突然想到一个问题,以前修改数据的时候抓包,发现只是TCP校验不正确,这就证明IP头的校验和和数据无关,后来为此我对TCP头重新计算,这个时候可以正常接发,所以证明也和TCP头无关,那么也就是说只和ETH头和IP头有关,但是在DDOS工具里是看不到ETH头的,也就证明只和IP头有关,试着写了个代码,实现我的想法是正确的。
  //计算IP校验
  pip_header = (PIP_HEADER)(PacketContent + sizeof(ETHHDR));
  pip_header>checksum = 0;
  pip_header>checksum = checksum((USHORT*)pip_header, sizeof(IP_HEADER));
  //KdPrint(("网络代码计算校验和: [0x%.4x] 原校验和: [0x%.4x]\n", ip_header.checksum, ipPacket>ip.checksum));
  //
  他只和IP头有关,修改了长度后直接把校验和置零然后重新计算即可。下面就是发送的代码,我只是重新申请了数据包:
  KdPrint(("数据 %s 大小 %d\n", pData, isizeof(PACKET)));
  NdisAllocateBuffer(&Status,&pDataBuffer, pAdapt>SendPacketPoolHandle, PacketContent, i);
  NdisChainBufferAtFront(MyPacket, pDataBuffer);
  NdisFreeMemory(PacketContent, 2048, 0);
  开始找转发的方法时候安焦上找到一个NDIS实现NAT的文章,他的方法有几步是错的,郁闷了我很久,至少我按他的方法实现要蓝屏。 后面就是自带的一句
  NdisSend(&Status, pAdapt>BindingHandle, MyPacket);
  然后下面都是他写的代码了,判断是否发送完成之类的,就不帖了。 这个的确实现了发出的数据里添加16字节数据,不过有个目前还有个问题,就是对方返回的一个ACK包,应该这个ACK包里有数据的校验,校验应该是返回给上层了的,因为我数据包修改了,校验和就不对,以前修改内容的时候就没出现这个问题,初步估计是校验只是校验了数据长度,至于是哪个位置是校验目前还不知道,还没研究出来。 当发送方收到校验时候会在两台机子之间交换一个很奇怪的包,应该是检测网络或者重置网卡用的,具体什么用我也还没研究出来,不过交换速度很快,瞬间就交换了上千个数据包,这不得不让人又想到了很万恶的拒绝服务攻击的方式。。。。 本文纯粹的学习笔记,希望给同样想写类似程序的人一个帮助。

上一页  [1] [2] 

责任编辑:小草

文章搜索:
 相关文章
热点资讯
资讯快报
热门课程培训